<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > stm32 NRF24L01+USART搞定有線和無線通信

          stm32 NRF24L01+USART搞定有線和無線通信

          作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
          前言

          一般進行遠程監(jiān)控時,2.4G無線通信是充當遠程數(shù)據(jù)傳輸?shù)囊环N方法。這時就需要在現(xiàn)場部分具備無線數(shù)據(jù)發(fā)送裝置,而在上位機部分由于一般只有串口,所以將采集到的數(shù)據(jù)送到電腦里又要在上位機端設(shè)計一個數(shù)據(jù)接收的適配器。這里基于stm32分別設(shè)計了現(xiàn)場部分和適配器部分,這里只是基本通信功能實現(xiàn)的講解,一些復雜的技術(shù)比如加密、可靠等要根據(jù)具體的應(yīng)用來設(shè)計~

          本文引用地址:http://www.ex-cimer.com/article/201611/318440.htm

          總體說明

          這里采用stm32作為MCU,采用nRF24L01作為2.4G通信模塊。其中適配器中僅僅采用了USARTNRF24L01兩個主要部分,負責將下位機通過2.4G發(fā)送過來的數(shù)據(jù)通過串口發(fā)送給上位機,或者將上位機的通過串口傳來的數(shù)據(jù)通過2.4G發(fā)送給下位機來實現(xiàn)遠程監(jiān)控(沒有采用uc-os操作系統(tǒng),也沒有界面,要用串口和上位機相連);其中下位機比較復雜,因為一般下位機是一個集成的系統(tǒng),包括從各種傳感器收集數(shù)據(jù)、向各種類型的驅(qū)動電路發(fā)送控制命令、將數(shù)據(jù)輸給打印機或顯示器、和無線通信或有線通信設(shè)備進行互相通信來實現(xiàn)數(shù)據(jù)傳輸?shù)龋@里的下位機比較簡單:采用uc-os實時操作系統(tǒng)+uc-gui負責界面顯示,外接7寸TFT液晶顯示屏,和適配器類似也包括USART和NRF24L01通信部分,但是因為有了操作系統(tǒng)和可視化交互界面,所以也有點不同,接下來開始介紹。

          適配器部分

          這里介紹的流程是以main函數(shù)為基準,廣度拓寬知識點,最后main函數(shù)說完,整個工程的細節(jié)也就大致能了解了~

          1 int main(void){2   uint8_t a=0;//LED高低電壓控制3   /* System Clocks Configuration */4   RCC_Configuration();                                              //系統(tǒng)時鐘設(shè)置    5   /*嵌套向量中斷控制器 6       說明了USART1搶占優(yōu)先級級別0(最多1位) ,和子優(yōu)先級級別0(最多7位) */ 7   NVIC_Configuration();                                              //中斷源配置8   /*對控制LED指示燈的IO口進行了初始化,將端口配置為推挽上拉輸出,口線速度為50Mhz。PA9,PA10端口復用為串口1的TX,RX。9   在配置某個口線時,首先應(yīng)對它所在的端口的時鐘進行使能。否則無法配置成功,由于用到了端口B, 因此要對這個端口的時鐘10   進行使能,同時由于用到復用IO口功能用于配置串口。因此還要使能AFIO(復用功能IO)時鐘。*/11   GPIO_Configuration();                                              //端口初始化12   SPI2_NRF24L01_Init();                                           //SPI2及NRF24L01接口初始化  13   USART_Config(USART1);                                              //串口1初始化14   /*NRF24L01設(shè)置為接收模式*/15   RX_Mode(); 16 17    while (1)18   {19     if(usart_rec_flag==1) //判斷是否收到一幀有效數(shù)據(jù)20     {                                                  21         usart_rec_flag=0;22         NRF_Send_Data(TxBufferRF,sizeof(TxBufferRF));23         if(a==0){GPIO_SetBits(GPIOB, GPIO_Pin_5);a=1;}          //LED1  明暗閃爍                24         else{GPIO_ResetBits(GPIOB, GPIO_Pin_5);a=0;}25     }26     if(rf_rec_flag==1)27     {28           rf_rec_flag=0;29            for(i=0;i<32;i++)//發(fā)送字符串30         {31             USART_SendChar(USART1,TxBufferUSART[i]);32         //    Delay(0x0ff00);33         }34     }35   }36 }

          第4行RCC初始化主要是系統(tǒng)時鐘和外設(shè)時鐘配置,這里注意要使能RCC_APB2Periph_USART1,當時忘了使能這個結(jié)果串口出現(xiàn)異常,我還以為是初始化和中斷向量什么的弄錯了呢,浪費了很長時間。

          1 /*--2 系統(tǒng)時鐘配置為72MHZ+外設(shè)時鐘配置*/ 3 void RCC_Configuration(void){4    SystemInit(); 5    RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 RCC_APB2Periph_GPIOA  RCC_APB2Periph_GPIOB RCC_APB2Periph_AFIO  , ENABLE);  6 }

          第7行中斷向量初始化設(shè)置,主要是設(shè)置串口接收中斷和NRF24L01中斷的,這樣設(shè)置好了之后當串口中斷被觸發(fā)時其對應(yīng)的中斷子程序?qū)⒈粓?zhí)行(這個科班的大概都知道這里就不多說了),所以我們就要在stm32f10x_it.c里實現(xiàn)他們各自的中斷子程序了(這個一會再詳細介紹,咱們先把整個框架了解下)。另外說一句,這里的的優(yōu)先級組將影響主優(yōu)先級和子優(yōu)先級數(shù)量具體請參考stm32f10X_的固件庫的NVIC.

          1 void NVIC_Configuration(void){2  /*  結(jié)構(gòu)聲明*/3   NVIC_InitTypeDef NVIC_InitStructure;4   EXTI_InitTypeDef EXTI_InitStructure;        5   6   /* 優(yōu)先級組 1  */    7   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);           8   9   /* Enable the USART1 Interrupt */10   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                     //設(shè)置串口1中斷11   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;             //搶占優(yōu)先級 012   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                //子優(yōu)先級為013   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能14   NVIC_Init(&NVIC_InitStructure);                                              15 16                                                                     17   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                    //NRF24L01 中斷響應(yīng)18   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;            //搶占優(yōu)先級 019   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                //子優(yōu)先級為120   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能21   NVIC_Init(&NVIC_InitStructure);                                                22 23   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);       //NRF24L01 IRQ  PA024   25   EXTI_InitStructure.EXTI_Line = EXTI_Line0;                       //NRF24L01 IRQ PA026   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;               //EXTI中斷27   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;           //下降沿觸發(fā)28   EXTI_InitStructure.EXTI_LineCmd = ENABLE;                           //使能29   EXTI_Init(&EXTI_InitStructure);    30 }

          第11行的GPIO初始化,主要是對通用IO口的屬性設(shè)置和初始化,這里一定要對串口所需的A9和A10配置好!

          1 void GPIO_Configuration(void){2   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                     //LED1控制--PB53   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;             //推挽輸出4   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;5   GPIO_Init(GPIOB, &GPIO_InitStructure);                     6 7   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                      //USART1 TX8   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;             //復用推挽輸出9   GPIO_Init(GPIOA, &GPIO_InitStructure);                     //A端口 10 11   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                  //USART1 RX12   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //復用開漏輸入13   GPIO_Init(GPIOA, &GPIO_InitStructure);                      //A端口 14 }

          第12行的SPI2_NRF24L01_Init();主要是驅(qū)動NRF24L01的接口初始化,因為NRF24L01采用的是SPI通信,所以這里免不了SPI的設(shè)置和相關(guān)操作了,不過幸好都封裝好了~像以前在51上做SPI就得自己模擬SPI,沒有示波器調(diào)試起來甚是坑~此外這里我已經(jīng)把NRF24L01的整個驅(qū)動都封裝在NRF24L01.c這個文件里了,當想用的時候只要在中斷向量里設(shè)置其中斷接收函數(shù),并在it.c里實現(xiàn)其接收函數(shù);一般主函數(shù)里用到的是其初始化函數(shù)SPI2_NRF24L01_Init();和RX_Mode();,當在過程中想利用NRF24L01向外發(fā)數(shù)據(jù)時只要調(diào)用函數(shù)void NRF_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes):

          1 /****************************************************************************2 * 名    稱:NRF_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes)3 * 功    能:將保存在接收緩存區(qū)的32字節(jié)的數(shù)據(jù)通過NRF24L01+發(fā)送出去4 * 入口參數(shù):data_buffer   待發(fā)送數(shù)據(jù)5             Nb_bytes      待發(fā)送數(shù)據(jù)長度6 * 出口參數(shù):無7 * 說    明:數(shù)據(jù)小于32,把有效數(shù)據(jù)外的空間用0填滿8 * 調(diào)用方法:RX_Mode();9 ****************************************************************************/10 void NRF_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes)11 {  12     uchar i=0;  13     MODE_CE(0);                                 //NRF 模式控制     14 15     SPI_RW_Reg(WRITE_REG1+STATUS,0xff);         //設(shè)置狀態(tài)寄存器初始化16     SPI_RW_Reg(0xe1,0);                         //清除TX FIFO寄存器17     SPI_RW_Reg(0xe2,0);                         //清除RX FIFO寄存器18     TX_Mode();                                 //設(shè)置為發(fā)送模式19     delay_ms(1);20     if(Nb_bytes<32){                         //當接收到的USB虛擬串口數(shù)據(jù)小于32,把有效數(shù)據(jù)外的空間用0填滿21         for(i=Nb_bytes;i<32;i++) data_buffer[i]=0;22     }23     MODE_CE(0);24       SPI_Write_Buf(WR_TX_PLOAD, data_buffer, TX_PLOAD_WIDTH);        //發(fā)送32字節(jié)的緩存區(qū)數(shù)據(jù)到NRF24L0125     MODE_CE(1);                                                        //保持10us以上,將數(shù)據(jù)發(fā)送出去        26 }

          第13行是USART初始化,包括波特率、數(shù)據(jù)位、停止位等~

          1 void USART_Config(USART_TypeDef* USARTx){2   USART_InitStructure.USART_BaudRate = 9600;                        //速率9600bps3   USART_InitStructure.USART_WordLength = USART_WordLength_8b;        //數(shù)據(jù)位8位4   USART_InitStructure.USART_StopBits = USART_StopBits_1;            //停止位1位5   USART_InitStructure.USART_Parity = USART_Parity_No;                //無校驗位6   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   //無硬件流控7   USART_InitStructure.USART_Mode = USART_Mode_Rx  USART_Mode_Tx;                    //收發(fā)模式8 9   /* Configure USART1 */10   USART_Init(USARTx, &USART_InitStructure);                            //配置串口參數(shù)函數(shù)11  12   13   /* Enable USART1 Receive and Transmit interrupts */14   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                    //使能接收中斷15   USART_ITConfig(USART1, USART_IT_TXE, ENABLE);                        //使能發(fā)送緩沖空中斷   16 17   /* Enable the USART1 */18   USART_Cmd(USART1, ENABLE);    19 }

          同樣的類似于NRF24L01一旦初始化之后,其數(shù)據(jù)接收一般采用中斷方式、數(shù)據(jù)發(fā)送一般采用直接發(fā)送的方式。所以在中斷向量里也要設(shè)置,也要在it.c中實現(xiàn)其接收中斷子函數(shù)。其發(fā)送直接調(diào)用stm32f10的固件庫函數(shù)(這里我稍加封裝了下):其實就是發(fā)送一個data之后要監(jiān)聽是否發(fā)送完成才能進行下次發(fā)送~

          1 void USART_SendChar(USART_TypeDef* USARTx,uint8_t data){2     USART_SendData(USARTx,data);3     while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);4 }

          接下來進入while循環(huán),不斷進行監(jiān)聽看是否有串口接收標志位置1或者無線模塊接收標志位置1,如果有表明相應(yīng)的有數(shù)據(jù)從該通道傳送過來。當是從串口傳來的數(shù)據(jù)表明數(shù)據(jù)是從上位機發(fā)送來的數(shù)據(jù),并且想把該數(shù)據(jù)通過2.4G發(fā)送出去,所以這里調(diào)用:NRF_Send_Data(TxBufferRF,sizeof(TxBufferRF));將數(shù)據(jù)發(fā)送出去;當數(shù)據(jù)是從2.4G通道中傳過來的,表明數(shù)據(jù)是從下位機傳送過來的想給上位機,于是調(diào)用串口發(fā)送函數(shù)將數(shù)據(jù)發(fā)送給上位機:USART_SendChar(USART1,TxBufferUSART[i]);

          看了上圖適配器端的數(shù)據(jù)交換過程就明白了串口中斷和無線中斷大致要干的事了,這里我就不多介紹,看看下面的代碼就明白了(在stm32f10x_it.c中),要再次提醒的是無論是串口還是無線其接收都是采用中斷,而發(fā)送采用循環(huán)直接發(fā)送,他們的中斷和中斷向量有關(guān)并要在stm32f10x_it.c里實現(xiàn)相應(yīng)的中斷子程序~



          1 /******************************************************************************/2 /*            STM32F10x Peripherals Interrupt Handlers                        */3 /******************************************************************************/4 5 /**6   * @brief  This function handles USART1 global interrupt request.7   * @param  None8   * @retval : None9   */10 void USART1_IRQHandler(void)      //串口1 中斷服務(wù)程序11 {12   unsigned int i;13   if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)       //判斷讀寄存器是否非空14   {    15     16     RxBufferUSART[RxCounter1++] = USART_ReceiveData(USART1);   //將讀寄存器的數(shù)據(jù)緩存到接收緩沖區(qū)里17     18     if(RxBufferUSART[RxCounter1-2]==0x0d&&RxBufferUSART[RxCounter1-1]==0x0a)     //判斷結(jié)束標志是否是0x0d 0x0a19     {20       for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i];          //將接收緩沖器的數(shù)據(jù)轉(zhuǎn)到發(fā)送緩沖區(qū),準備轉(zhuǎn)發(fā)21       usart_rec_flag=1;                                                             //接收成功標志22       TxBufferRF[RxCounter1]=0;                                             //發(fā)送緩沖區(qū)結(jié)束符    23       TxCounter1=RxCounter1;24       RxCounter1=0;25     }26   }27   28   if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)                   //這段是為了避免STM32 USART 第一個字節(jié)發(fā)不出去的BUG 29   { 30      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);                         //禁止發(fā)緩沖器空中斷, 31   }    32 }  33 /*******************************************************************************34 * Function Name  : EXTI0 中斷函數(shù)35 * Description    : NRF24L01中斷服務(wù)程序36 * Input          : None37 * Output         : None38 * Return         : None39 *******************************************************************************/40 void EXTI0_IRQHandler(void){41     u8 i=0;42      u8 status;    43     if(EXTI_GetITStatus(EXTI_Line0) != RESET)            //判斷是否產(chǎn)生了EXTI0中斷44       {45         if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0){ //判斷是否是PA0線變低            46             status=SPI_Read(READ_REG1+STATUS);            // 讀取狀態(tài)寄存其來判斷數(shù)據(jù)接收狀況    47             if(status & 0x40)                            // 判斷是否接收到數(shù)據(jù)                   48             {            49                 //GPIO_ResetBits(GPIOB, GPIO_Pin_5);   50                  SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);  //從接收緩沖區(qū)里讀出數(shù)據(jù)51                 for(i=0; i<32; i++)TxBufferUSART[i] = rx_buf[i];  //向USB 端點1的緩沖區(qū)里放置數(shù)據(jù)      52                 rf_rec_flag=1;53             }54             else if((status &0x10)>0){                     //發(fā)射達到最大復發(fā)次數(shù)                55                 SPI_RW_Reg(0xe1,0);                          //清除發(fā)送緩沖區(qū)                  56                 RX_Mode();                                 //進入接收模式                   57             }58             else if((status &0x20)>0){                     //發(fā)射后收到應(yīng)答 59                 GPIO_SetBits(GPIOB, GPIO_Pin_5);   60                 SPI_RW_Reg(0xe1,0);                         //清除發(fā)送緩沖區(qū)              61                 RX_Mode();                                 //進入接收模式                   62             }63             SPI_RW_Reg(WRITE_REG1+STATUS, status);         //清除07寄存器標志64         }        65         EXTI_ClearITPendingBit(EXTI_Line0);             //清除EXTI0上的中斷標志              66     } 67 }
          串口和無線接收中斷子程序

          下位機部分

          上面說過一般具有遠程通信能力的嵌入式系統(tǒng)其下位機部分往往要干很多事,這里我們采用stm32作為MCU并搭載uc-OS實時操作系統(tǒng)負責任務(wù)調(diào)度,同時采用7寸TFT彩屏和uc-GUI設(shè)計可視化人機交互界面。其中任務(wù)包括主任務(wù)、界面任務(wù)和觸摸任務(wù),主任務(wù)負責建立其他任務(wù),界面任務(wù)中將包含整個人機交互界面的界面刷新邏輯,觸摸任務(wù)負責獲取觸摸位置數(shù)據(jù)獲取~

          這里我們還是得從main函數(shù)先說起:首先在main函數(shù)中進行相關(guān)初始化,然后建立主任務(wù)并啟動uc-OS內(nèi)核;接著在主任務(wù)中調(diào)用App_TaskCreate();分別建立界面任務(wù)和觸摸任務(wù)(如下每個任務(wù)的建立類似,要給出指向任務(wù)代碼的指針、任務(wù)執(zhí)行時傳遞給任務(wù)的參數(shù)的指針,分配給這個任務(wù)的棧信息,任務(wù)優(yōu)先級等)。這樣當任務(wù)建立好之后,其執(zhí)行權(quán)就由操作系統(tǒng)調(diào)度了~

          1 static  void App_TaskCreate(void)2 {3    /*  建立用戶界面任務(wù) */4    OSTaskCreateExt(AppTaskUserIF,                                               //指向任務(wù)代碼的指針5                        (void *)0,                                                   //任務(wù)開始執(zhí)行時,傳遞給任務(wù)的參數(shù)的指針6                        (OS_STK *)&AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE-1],  //分配給任務(wù)的堆棧的棧頂指針   從頂向下遞減7                     APP_TASK_USER_IF_PRIO,                                       //分配給任務(wù)的優(yōu)先級8                     APP_TASK_USER_IF_PRIO,                                       //預(yù)備給以后版本的特殊標識符,在現(xiàn)行版本同任務(wù)優(yōu)先級9                     (OS_STK *)&AppTaskUserIFStk[0],                               //指向任務(wù)堆棧棧底的指針,用于堆棧的檢驗10                     APP_TASK_USER_IF_STK_SIZE,                                    //指定堆棧的容量,用于堆棧的檢驗11                     (void *)0,                                                    //指向用戶附加的數(shù)據(jù)域的指針,用來擴展任務(wù)的任務(wù)控制塊12                     OS_TASK_OPT_STK_CHKOS_TASK_OPT_STK_CLR);                    //選項,指定是否允許堆棧檢驗,是否將堆棧清0,任務(wù)是否要13                                                                                 //進行浮點運算等等。14                     15    /* 建立觸摸驅(qū)動任務(wù) */16    OSTaskCreateExt(AppTaskKbd,17                        (void *)0,18                     (OS_STK *)&AppTaskKbdStk[APP_TASK_KBD_STK_SIZE-1],19                     APP_TASK_KBD_PRIO,20                     APP_TASK_KBD_PRIO,21                     (OS_STK *)&AppTaskKbdStk[0],22                     APP_TASK_KBD_STK_SIZE,23                     (void *)0,24                     OS_TASK_OPT_STK_CHKOS_TASK_OPT_STK_CLR);   25 26 }

          這里以界面任務(wù)為例:因為我們在建立界面任務(wù)時已經(jīng)指定其任務(wù)代碼指針AppTaskUserIF,所以這里來寫其對應(yīng)的函數(shù)(也就是說這里是界面任務(wù)的入口)。從下面的代碼可以看出進入界面任務(wù)時首先對uc-GUI進行初始化,然后進入死循環(huán)不斷執(zhí)行Fun()函數(shù)(有人會疑惑:這里while死循環(huán)不就只能死在這里嗎?怎么執(zhí)行其他任務(wù)呢?,這就是具有操作系統(tǒng)和不具有操作系統(tǒng)的不同啦~雖然這里是while死循環(huán),但是當OS要把CPU占有權(quán)分給其他任務(wù)時就會把當前執(zhí)行的任務(wù)的信息壓入其對應(yīng)的??臻g,當再次要把CPU分配給該任務(wù)時,則把棧里保存的上次執(zhí)行的情況拿出來繼續(xù)執(zhí)行,從而實現(xiàn)搶占與多任務(wù)的效果!)

          1 static  void  AppTaskUserIF (void *p_arg)2 {                                               3  (void)p_arg;                                    4   GUI_Init();                    //ucgui初始化 5   while(1) 6   {    7      Fun();                     //界面主程序8   }9 }

          所以接下來我們主要看Fun.c里的Fun函數(shù):雖然代碼有點長,但是很好理解,其核心思路就是建立整個界面并對界面中的每個控件進行相關(guān)設(shè)置同時獲得其句柄,在最后又進入了while死循環(huán),在循環(huán)中不斷檢測2.4G是否接受到數(shù)據(jù)(和適配器端類似也是中斷子程序中收數(shù)據(jù)然后置接收標志為1的),然后根據(jù)從2.4G收到的數(shù)據(jù)來刷新文本顯示區(qū);下面一個if判斷speed_change_flag是否有效來向串口發(fā)送相應(yīng)的數(shù)據(jù)。那么我們的問題又來了:這個speed_change_flag是在哪里被改變的呢?這個我們就要參看窗口回調(diào)函數(shù)了!這里的窗口回調(diào)函數(shù)是窗口動作響應(yīng)函數(shù)(就像安卓開發(fā)里的按鈕監(jiān)聽或MFC里的按鈕點擊事件等),一旦窗口里的控件有相應(yīng)的觸發(fā)動作就會調(diào)用該函數(shù),并把事件類型封裝在WM_MESSAGE里傳過來,在該函數(shù)里對該消息進行解析并作出相應(yīng)的動作即可(非常像Win32!!!我懷疑做這個uc-GUI的人有copy微軟的嫌疑,?(^∇^*)隨便猜測,如有雷同,純屬巧合)。這樣我們就很容易找到send按鈕的監(jiān)聽用于將數(shù)據(jù)通過NRF24L01發(fā)送出去的相關(guān)操作,也就明白了滑動條監(jiān)聽用來改變speed1~5.上面說了這么多,少了介紹整個界面是怎么建立的了~其實整個窗體的布局都要放在一個結(jié)構(gòu)體里,然后在fun()函數(shù)里調(diào)用hWin = GUI_CreateDialogBox(aDialogCreate, GUI_COUNTOF(aDialogCreate), _cbCallback, 0, 0, 0);根據(jù)定義的窗口資源和回調(diào)函數(shù)進行窗體的建立~這樣我們就圓滿地理解了stm32基于uc-OS并搭載uc-GUI的運行邏輯啦!



          1 void Fun(void) {   2   GUI_CURSOR_Show();                                        //打開鼠標圖形顯示  3   4   /* 建立對話框時,包含了資源列表,資源數(shù)目, 并且指定了用于動作響應(yīng)的回調(diào)函數(shù)  */5   hWin = GUI_CreateDialogBox(aDialogCreate, GUI_COUNTOF(aDialogCreate), _cbCallback, 0, 0, 0);6 7   FRAMEWIN_SetFont(hWin, &GUI_FontComic18B_1);                  //對話框字體設(shè)置 8   FRAMEWIN_SetClientColor(hWin, GUI_BLACK);                      //對話框的窗體顏色是黑色9   memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32);   //將長度為32字節(jié)的發(fā)送字符串拷貝到發(fā)送緩沖區(qū),10   memcpy(rx_buf, "", 32);                                    //將接收緩存區(qū)清空11  12   /* 獲得文本框句柄 */        13   text1 = WM_GetDialogItem(hWin, GUI_ID_TEXT0);                //獲得對話框里GUI_ID_TEXT0項目(文本框Send Text Area)的句柄14   text2 = WM_GetDialogItem(hWin, GUI_ID_TEXT1);                //獲得對話框里GUI_ID_TEXT1項目(文本框Receive Text Area)的句柄15   text3 = WM_GetDialogItem(hWin, GUI_ID_TEXT2);                //獲得對話框里GUI_ID_TEXT2項目(文本框2M BPS)的句柄16   text4 = WM_GetDialogItem(hWin, GUI_ID_TEXT3);                //獲得對話框里GUI_ID_TEXT3項目(文本框1M BPS)的句柄17   text6 = WM_GetDialogItem(hWin, GUI_ID_TEXT5);                //獲得對話框里GUI_ID_TEXT5項目(文本框250K BPS)的句柄18   text5 = WM_GetDialogItem(hWin, GUI_ID_TEXT4);                //獲得對話框里GUI_ID_TEXT4項目(狀態(tài)字符文本框)的句柄  19   /* 設(shè)置文本框字體 */20   TEXT_SetFont(text1,pFont);                                //設(shè)置對話框里文本框Send Text Area的字體21   TEXT_SetFont(text2,pFont);                                //設(shè)置對話框里文本框Receive Text Area的字體22   TEXT_SetFont(text3,pFont18);                                //設(shè)置對話框里文本框2M BPS的字體23   TEXT_SetFont(text4,pFont18);                                //設(shè)置對話框里文本框1M BPS的字體24   TEXT_SetFont(text6,pFont18);                                //設(shè)置對話框里文本框250K BPS的字體25   TEXT_SetFont(text5,pFont);                                //設(shè)置對話框里狀態(tài)字符文本框的字體26   /* 設(shè)置文本框顏色 */27   TEXT_SetTextColor(text1,GUI_GREEN);                        //設(shè)置對話框里文本框Send Text Area的字體顏色28   TEXT_SetTextColor(text2,GUI_GREEN );                        //設(shè)置對話框里文本框Receive Text Area的字體顏色29   TEXT_SetTextColor(text3,GUI_YELLOW);                        //設(shè)置對話框里文本框2M BPS的字體顏色30   TEXT_SetTextColor(text4,GUI_YELLOW);                        //設(shè)置對話框里文本框1M BPS的字體顏色31   TEXT_SetTextColor(text6,GUI_YELLOW);                       //設(shè)置對話框里文本框250K BPS的字體顏色32   TEXT_SetTextColor(text5,GUI_YELLOW);                        //設(shè)置對話框里狀態(tài)字符文本框的字體顏色33   TEXT_SetBkColor(text5,GUI_BLUE);                            //設(shè)置對話框里狀態(tài)字符文本框的背景顏色34 35   /* 編輯框相關(guān) */36   edit1 = WM_GetDialogItem(hWin, GUI_ID_EDIT1);                //獲得對話框里GUI_ID_EDIT1項目(編輯框 發(fā)送字符串顯示區(qū))的句柄37   EDIT_SetFont(edit1,pFont18);                                //設(shè)置對話框里編輯框 發(fā)送字符串顯示區(qū)的字體38   EDIT_SetText(edit1,(const char *)tx_buf);                    //設(shè)置對話框里編輯框 發(fā)送字符串顯示區(qū)的字符串39   edit2 = WM_GetDialogItem(hWin, GUI_ID_EDIT2);                //獲得對話框里GUI_ID_EDIT2項目(編輯框 接收字符串顯示區(qū))的句柄40   EDIT_SetFont(edit2,pFont18);                                //設(shè)置對話框里編輯框 接收字符串顯示區(qū)的字體41   EDIT_SetText(edit2,(const char *)rx_buf);                    //設(shè)置對話框里編輯框 接收字符串顯示區(qū)的字符串42 43   /* 按鈕相關(guān) */44   bt[0]=WM_GetDialogItem(hWin,GUI_ID_BUTTON0);                //獲得對話框里GUI_ID_BUTTON0項目(按鍵SEND)的句柄45   bt[1]=WM_GetDialogItem(hWin, GUI_ID_BUTTON2);                //獲得對話框里GUI_ID_BUTTON2項目(按鍵CLEAR)的句柄46   BUTTON_SetFont(bt[0],pFont);                                //設(shè)置對話框里按鍵SEND的字體47   BUTTON_SetFont(bt[1],pFont);                                //設(shè)置對話框里按鍵CLEAR的字體48   BUTTON_SetTextColor(bt[0],0,GUI_WHITE);                     //設(shè)置對話框里按鍵SEND未被按下的字體顏色49   BUTTON_SetTextColor(bt[1],0,GUI_WHITE);                    //設(shè)置對話框里按鍵CLEAR未被按下的字體顏色50 51   /* List相關(guān) */            52   nrf_Pipe=0;                                                //NRF24L01初始發(fā)射通道設(shè)置為053   list1 = WM_GetDialogItem(hWin, GUI_ID_LISTBOX0);            //獲得對話框里GUI_ID_LISTBOX0項目(列表框-通道選擇)的句柄     54   LISTBOX_SetText(list1, _apListBox);                        //設(shè)置對話框里列表框-通道選擇里的條目55   LISTBOX_SetFont(list1,pFont18);                            //設(shè)置對話框里列表框-通道選擇的字體56   LISTBOX_SetSel(list1,nrf_Pipe);                            //設(shè)置對話框里列表框-通道選擇的焦點選擇57   SCROLLBAR_CreateAttached(list1, SCROLLBAR_CF_VERTICAL);    //設(shè)置對話框里列表框-通道選擇的卷動方向為下拉        58 59   /* Radio按鈕相關(guān) */        60   rd0 = WM_GetDialogItem(hWin, GUI_ID_RADIO0);                //獲得對話框里GUI_ID_RADIO0項目(點選框-速率選擇)的句柄61   nrf_baud=0;                                                //NRF24L01速率 初始為2MPS62   RADIO_SetValue(rd0,0);                                    //設(shè)置對話框里點選框-速率選擇的焦點選擇63   RX_Mode();                                                //NRF24L01進入接收模式 64  65   /* 獲得slider部件的句柄 */    66   slider1 = WM_GetDialogItem(hWin, GUI_ID_SLIDER1);67   slider2 = WM_GetDialogItem(hWin, GUI_ID_SLIDER2);68   slider3 = WM_GetDialogItem(hWin, GUI_ID_SLIDER3);69   slider4 = WM_GetDialogItem(hWin, GUI_ID_SLIDER4);70   slider5 = WM_GetDialogItem(hWin, GUI_ID_SLIDER5);71   /* 設(shè)置slider部件的取值范圍-8-8*/  72   SLIDER_SetRange(slider1,-8,8);    73   SLIDER_SetRange(slider2,-8,8);74   SLIDER_SetRange(slider3,-8,8);75   SLIDER_SetRange(slider4,-8,8);76   SLIDER_SetRange(slider5,-8,8);77   /* 設(shè)置slider部件的值*/      78   SLIDER_SetValue(slider1,0);  79   SLIDER_SetValue(slider2,0);    80   SLIDER_SetValue(slider3,0);  81   SLIDER_SetValue(slider4,0);  82   SLIDER_SetValue(slider5,0);  83   /* 獲取文本框句柄 */84   text_speed1 = WM_GetDialogItem(hWin, GUI_ID_TEXT_SPEED1);    85   text_speed2 = WM_GetDialogItem(hWin, GUI_ID_TEXT_SPEED2);    86   text_speed3 = WM_GetDialogItem(hWin, GUI_ID_TEXT_SPEED3);    87   text_speed4 = WM_GetDialogItem(hWin, GUI_ID_TEXT_SPEED4);    88   text_speed5 = WM_GetDialogItem(hWin, GUI_ID_TEXT_SPEED5);    89   /* 設(shè)置文本框字體 */90   TEXT_SetFont(text_speed1,pFont18);91   TEXT_SetFont(text_speed2,pFont18);92   TEXT_SetFont(text_speed3,pFont18);93   TEXT_SetFont(text_speed4,pFont18);94   TEXT_SetFont(text_speed5,pFont18);                                    95   /* 設(shè)置文本框顏色 */96   TEXT_SetTextColor(text_speed1,GUI_YELLOW);        97   TEXT_SetTextColor(text_speed2,GUI_YELLOW);        98   TEXT_SetTextColor(text_speed3,GUI_YELLOW);        99   TEXT_SetTextColor(text_speed4,GUI_YELLOW);        100   TEXT_SetTextColor(text_speed5,GUI_YELLOW);        101 102   speed_change_flag=0;103 104   while (1)105   {               106     if(Rx_Succ==1){                                            //當NRF24L01接收到有效數(shù)據(jù)107         EDIT_SetText(edit2,(const char *)rx_buf);            //將接收緩沖區(qū)的字符寫入到接收字符編輯框內(nèi)108         TEXT_SetText(text5,(const char *)status_buf);        //將狀態(tài)文本緩沖區(qū)的字符寫入到狀態(tài)文本框內(nèi)109         Rx_Succ=0; 110 //        for(i=0;i
          Fun()


          1 /****************************************************************************2 * 名    稱:static void _cbCallback(WM_MESSAGE * pMsg)3 * 功    能:ucgui回調(diào)函數(shù),是作為對話框動作響應(yīng)的函數(shù)4 * 入口參數(shù):無5 * 出口參數(shù):無6 * 說    明:7 * 調(diào)用方法:8 ****************************************************************************/  9 static void _cbCallback(WM_MESSAGE * pMsg) {10   int NCode, Id;11   switch (pMsg->MsgId) {12     case WM_NOTIFY_PARENT:                          //通知父窗口有事件在窗口部件上發(fā)生13       Id    = WM_GetId(pMsg->hWinSrc);            //獲得對話框窗口里發(fā)生事件的部件的ID14       NCode = pMsg->Data.v;                       //通知代碼15       switch (NCode) {16         case WM_NOTIFICATION_RELEASED:            //窗體部件動作被釋放             17           if (Id == GUI_ID_BUTTON2) {             //按鍵CLEAR被松開18             memcpy(status_buf, "", 20);              //清空狀態(tài)文本緩沖區(qū) 19             memcpy(rx_buf, "", 32);                  //清空接收文本緩沖區(qū)         20             TEXT_SetText(text5,(const char *)status_buf);           //清空狀態(tài)文本框    21             EDIT_SetText(edit2,(const char *)rx_buf);            //清空接收字符編輯框22             memcpy(tx_buf, "", 32);                //清空發(fā)送文本緩沖區(qū)23             NRF24L01_TXBUF(tx_buf,32);            //將發(fā)送字符緩沖區(qū)的字符通過NRF24L01發(fā)送出去        24           }          25           else if (Id == GUI_ID_BUTTON0) {      //按鍵SEND 被松開26               memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32);      //將32字節(jié)的文本拷貝到發(fā)送文本緩沖區(qū)27             memcpy(rx_buf, "", 32);                //清空接收文本緩沖區(qū)     28             memcpy(status_buf, "", 20);            //清空狀態(tài)文本緩沖區(qū) 29             EDIT_SetText(edit2,(const char *)rx_buf);            //清空接收字符編輯框    30             NRF24L01_TXBUF(tx_buf,32);            //將發(fā)送字符緩沖區(qū)的字符通過NRF24L01發(fā)送出去31             memcpy(tx_buf, "", 32);                //清空發(fā)送文本緩沖區(qū)32             TEXT_SetText(text5,(const char *)status_buf);        //清空狀態(tài)文本框               33           }34           else if (Id == GUI_ID_RADIO0) {       //NRF24L01無線速率點選框點選動作完成35               nrf_baud= RADIO_GetValue(rd0);        //獲得速率表示值36             RX_Mode();                            //進入接收模式            37           }38           else if (Id == GUI_ID_LISTBOX0){      //NRF24L01無線通道選擇動作39             nrf_Pipe= LISTBOX_GetSel(list1);    //獲得NRF24LL01無線通道表示值             40             RX_Mode();                           //進入接收模式     41           }else if(Id == GUI_ID_SLIDER1){       //slider1 的值被改變42             speed1=SLIDER_GetValue(slider1);//獲得slider1的值43             if(speed1>0){44                speed_show[0]=+;45                speed_show[1]=0+speed1;46                control_data=8+speed1;47             }else if(speed1<0){48                speed_show[0]=-;49                speed_show[1]=0-speed1;50                control_data=16-speed1;51             }else{52                speed_show[0]= ;53                speed_show[1]=0;54                control_data=0;55             }56 //            USART_SendChar(USART1,control_data);57             TEXT_SetText(text_speed1,speed_show);58             speed_change_flag=1;                     59           }else if(Id == GUI_ID_SLIDER2){       //slider2 的值被改變60             speed2=SLIDER_GetValue(slider2);//獲得slider2的值61             if(speed2>0){62                speed_show[0]=+;63                speed_show[1]=0+speed2;64                control_data=32+8+speed2;65             }else if(speed2<0){66                speed_show[0]=-;67                speed_show[1]=0-speed2;68                control_data=32+16-speed2;69             }else{70                speed_show[0]= ;71                speed_show[1]=0;72                control_data=0;73             }74             TEXT_SetText(text_speed2,speed_show);75             speed_change_flag=1;            76           }else if(Id == GUI_ID_SLIDER3){       //slider3 的值被改變77             speed3=SLIDER_GetValue(slider3);//獲得slider3的值78             if(speed3>0){79                speed_show[0]=+;80                speed_show[1]=0+speed3;81                control_data=64+8+speed3;82             }else if(speed3<0){83                speed_show[0]=-;84                speed_show[1]=0-speed3;85                control_data=64+16-speed3;86             }else{87                speed_show[0]= ;88                speed_show[1]=0;89                control_data=0;90             }91             TEXT_SetText(text_speed3,speed_show);92             speed_change_flag=1;      93           }else if(Id == GUI_ID_SLIDER4){       //slider4 的值被改變94             speed4=SLIDER_GetValue(slider4);//獲得slider4的值95             if(speed4>0){96                speed_show[0]=+;97                speed_show[1]=0+speed4;98                control_data=96+8+speed4;99             }else if(speed4<0){100                speed_show[0]=-;      101                speed_show[1]=0-speed4;102                control_data=96+16-speed4;103             }else{104                speed_show[0]= ;105                speed_show[1]=0;106                control_data=0;107             }108             TEXT_SetText(text_speed4,speed_show);109             speed_change_flag=1;      110           }else if(Id == GUI_ID_SLIDER5){       //slider5 的值被改變speed5=SLIDER_GetValue(slider5);//獲得slider5的值112             if(speed5>0){113                speed_show[0]=+;114                speed_show[1]=0+speed5;115                control_data=128+8+speed5;116             }else if(speed5<0){117                speed_show[0]=-;118                speed_show[1]=0-speed5;119                control_data=128+16-speed5;120             }else{121                speed_show[0]= ;122                speed_show[1]=0;123                control_data=0;124             }125             TEXT_SetText(text_speed5,speed_show);126             speed_change_flag=1;      127           }128          break;129          default: break;130       }        131     default:132       WM_DefaultProc(pMsg);                        //默認程序來處理消息133       break;134   }135 }
          窗口回調(diào)函數(shù)
          1 /* 定義了對話框資源列表 */2 static const GUI_WIDGET_CREATE_INFO aDialogCreate[] = {3   //建立窗體, 大小是800X480  原點在0,04   { FRAMEWIN_CreateIndirect, "http://beautifulzzzz", 0,0,0, 800, 480, FRAMEWIN_CF_ACTIVE },5   { BUTTON_CreateIndirect,   "SEND",    GUI_ID_BUTTON0,       0,    395,  200,  55 },6  7   { BUTTON_CreateIndirect,   "CLEAR", GUI_ID_BUTTON2,   200,    395, 200,  55 },8   { EDIT_CreateIndirect,     "",       GUI_ID_EDIT1,    0,   190, 400,  65, EDIT_CF_LEFT, 50 },9   { EDIT_CreateIndirect,     "",       GUI_ID_EDIT2,    0,   290, 400,  65, EDIT_CF_LEFT, 50 },10   11   //建立TEXT控件,起點是窗體的X,X,大小XXY  文字左對齊12   { TEXT_CreateIndirect,     "Send Text Area",  GUI_ID_TEXT0,   1,   160,  400,  25, TEXT_CF_LEFT },13   { TEXT_CreateIndirect,     "Receive Text Area ",  GUI_ID_TEXT1,     1,   263,  400, 25, TEXT_CF_LEFT },14  15   { TEXT_CreateIndirect,     "2M bps",  GUI_ID_TEXT2,   23,   22,  140,  25, TEXT_CF_LEFT },16   { TEXT_CreateIndirect,     "1M bps",  GUI_ID_TEXT3,     23,   42,  140,  25, TEXT_CF_LEFT },17   { TEXT_CreateIndirect,     "250K bps",  GUI_ID_TEXT5,     23,   62,  140,  25, TEXT_CF_LEFT },18   19   { TEXT_CreateIndirect,     "",  GUI_ID_TEXT4,     0,   120,  400,  25, TEXT_CF_LEFT },20 21   { RADIO_CreateIndirect,     "Receive Mode",  GUI_ID_RADIO0,     3,   33,  40,  52, RADIO_TEXTPOS_LEFT,3},22 23   { LISTBOX_CreateIndirect,  "",       GUI_ID_LISTBOX0,  134,    13,  130,  90, 0, 0 },24 25    //建立滑塊26   { SLIDER_CreateIndirect,   NULL,     GUI_ID_SLIDER1,  440,  60, 320, 25, 0, 0 },27   { SLIDER_CreateIndirect,   NULL,     GUI_ID_SLIDER2,  440,  120, 320, 25, 0, 0 },28   { SLIDER_CreateIndirect,   NULL,     GUI_ID_SLIDER3,  440,  180, 320, 25, 0, 0 },29   { SLIDER_CreateIndirect,   NULL,     GUI_ID_SLIDER4,  440,  240, 320, 25, 0, 0 },30   { SLIDER_CreateIndirect,   NULL,     GUI_ID_SLIDER5,  440,  300, 320, 25, 0, 0 },31   //建立滑塊對應(yīng)的text32   { TEXT_CreateIndirect,     "0",  GUI_ID_TEXT_SPEED1,   770,   60,   25,  25, TEXT_CF_LEFT },33   { TEXT_CreateIndirect,     "0",  GUI_ID_TEXT_SPEED2,   770,   120,  25,  25, TEXT_CF_LEFT },34   { TEXT_CreateIndirect,     "0",  GUI_ID_TEXT_SPEED3,   770,   180,  25,  25, TEXT_CF_LEFT },35   { TEXT_CreateIndirect,     "0",  GUI_ID_TEXT_SPEED4,   770,   240,  25,  25, TEXT_CF_LEFT },36   { TEXT_CreateIndirect,     "0",  GUI_ID_TEXT_SPEED5,   770,   300,  25,  25, TEXT_CF_LEFT },37 };

          還要回過頭說說我們的USART和NRF24L01,他們的初始化要看main函數(shù)中的BSP_Init();函數(shù),該函數(shù)負相關(guān)硬件的初始化設(shè)置(中文意思是板級支持包初始化函數(shù),因為uc-OS可以并不只限于stm32單片機,所以這里要根據(jù)不同平臺進行相應(yīng)的設(shè)置)。該函數(shù)位于bsp.c函數(shù)中,其作用相當于將以前我們在main函數(shù)中進行的相關(guān)硬件初始化單獨拿出來封裝成一個函數(shù)而已~但是,串口和無線對應(yīng)的中斷接收程序卻有點不一樣,因為這里是操作系統(tǒng),所以在每個中斷子程序前要調(diào)用OS_ENTER_CRITICAL();保存當前的全局中斷標志,然后OSIntNesting++;中斷嵌套深度加1,最后調(diào)用OS_EXIT_CRITICAL();恢復全局中斷標志進入正常的中斷處理,此外在中斷響應(yīng)函數(shù)最后要調(diào)用OSIntExit(); 檢測如果有更高優(yōu)先級的任務(wù)就緒了,則執(zhí)行一次任務(wù)切換。



          1 /*******************************************************************************2 * Function Name  : USART1_IRQHandler3 * Description    : This function handles USART1 global interrupt request.4 * Input          : None5 * Output         : None6 * Return         : None7 *******************************************************************************/8 void USART1_IRQHandler(void)9 { 10     unsigned int i;11     OS_CPU_SR  cpu_sr;12     OS_ENTER_CRITICAL();  //保存全局中斷標志,關(guān)總中斷 Tell uC/OS-II that we are starting an ISR13     OSIntNesting++;14     OS_EXIT_CRITICAL();      //恢復全局中斷曛?        15 16     if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)       //判斷讀寄存器是否非空17     {    18         RxBufferUSART[RxCounter1++] = USART_ReceiveData(USART1);   //將讀寄存器的數(shù)據(jù)緩存到接收緩沖區(qū)里19         if(RxBufferUSART[RxCounter1-2]==0x0d&&RxBufferUSART[RxCounter1-1]==0x0a)     //判斷結(jié)束標志是否是0x0d 0x0a20         {21             for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i];          //將接收緩沖器的數(shù)據(jù)轉(zhuǎn)到發(fā)送緩沖區(qū),準備轉(zhuǎn)發(fā)22             usart_rec_flag=1;                                                             //接收成功標志23             TxBufferRF[RxCounter1]=0;                                             //發(fā)送緩沖區(qū)結(jié)束符    24             TxCounter1=RxCounter1;25             RxCounter1=0;26         }27     }28     if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)                   //這段是為了避免STM32 USART 第一個字節(jié)發(fā)不出去的BUG 29     { 30         USART_ITConfig(USART1, USART_IT_TXE, DISABLE);                         //禁止發(fā)緩沖器空中斷, 31     }    32     OSIntExit();           //在os_core.c文件里定義,如果有更高優(yōu)先級的任務(wù)就緒了,則執(zhí)行一次任務(wù)切換    33 }34 /////////////////////////////35 void EXTI0_IRQHandler(void)36 { 37   unsigned char status,i;38   OS_CPU_SR  cpu_sr;39   OS_ENTER_CRITICAL();  //保存全局中斷標志,關(guān)總中斷 Tell uC/OS-II that we are starting an ISR40   OSIntNesting++;41   OS_EXIT_CRITICAL();      //恢復全局中斷標志             42   43   if(EXTI_GetITStatus(EXTI_Line0) != RESET)            //判斷是否產(chǎn)生了EXTI0中斷44   {45       if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0){ //判斷是否是PA0線變低            46         status=SPI_Read(READ_REG1+STATUS);            // 讀取狀態(tài)寄存其來判斷數(shù)據(jù)接收狀況    47         if(status & 0x40)                            // 判斷是否接收到數(shù)據(jù)                   48         {                                                         49              SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);  //從接收緩沖區(qū)里讀出數(shù)據(jù) 50             for(i=0; i<32; i++){                              //向USB 端點1的緩沖區(qū)里放置數(shù)據(jù)51                 TxBufferUSART[i] = rx_buf[i];     52             }53             rf_rec_flag=1;          54             if((status&0x0e)<=0x0a){                           55                nrf_Pipe_r=(status&0x0e)>>1;                      //讀出是在哪個通道接收的56             }57             else nrf_Pipe_r=0;                     58             Rx_Succ=1;            //讀取數(shù)據(jù)完成標志59             /* 根據(jù)讀出的接收通道號,將相應(yīng)信息寫入狀態(tài)文本緩沖區(qū) */60             if(nrf_Pipe_r==0) memcpy(status_buf, "Pipe 0 Recive OK!   ", 20);           61             else if(nrf_Pipe_r==1) memcpy(status_buf, "Pipe 1 Recive OK!   ", 20);62             else if(nrf_Pipe_r==2) memcpy(status_buf, "Pipe 2 Recive OK!   ", 20);63             else if(nrf_Pipe_r==3) memcpy(status_buf, "Pipe 3 Recive OK!   ", 20);64             else if(nrf_Pipe_r==4) memcpy(status_buf, "Pipe 4 Recive OK!   ", 20);65             else if(nrf_Pipe_r==5) memcpy(status_buf, "Pipe 5 Recive OK!   ", 20);66         }67         else if((status &0x10)>0){                     //發(fā)射達到最大復發(fā)次數(shù)                68             SPI_RW_Reg(0xe1,0);                          //清除發(fā)送緩沖區(qū)                  69             RX_Mode();                                 //進入接收模式                                 70             Rx_Succ=1;                                                                                    71             /* 根據(jù)發(fā)送通道,將相應(yīng)信息寫入狀態(tài)文本緩沖區(qū) */72             if(nrf_Pipe==0) memcpy(status_buf, "Pipe 0 NO ACK!      ", 20);73             else if(nrf_Pipe==1) memcpy(status_buf, "Pipe 1 NO ACK!      ", 20);74             else if(nrf_Pipe==2) memcpy(status_buf, "Pipe 2 NO ACK!      ", 20);75             else if(nrf_Pipe==3) memcpy(status_buf, "Pipe 3 NO ACK!      ", 20);  76             else if(nrf_Pipe==4) memcpy(status_buf, "Pipe 4 NO ACK!      ", 20);77             else if(nrf_Pipe==5) memcpy(status_buf, "Pipe 5 NO ACK!      ", 20);            78         }79         else if((status &0x20)>0){                     //發(fā)射后收到應(yīng)答             80             SPI_RW_Reg(0xe1,0);                         //清除發(fā)送緩沖區(qū)              81             RX_Mode();                                 //進入接收模式82             Rx_Succ=1;83             /* 根據(jù)發(fā)送通道,將相應(yīng)信息寫入狀態(tài)文本緩沖區(qū) */84             if(nrf_Pipe==0) memcpy(status_buf, "Pipe 0 Send OK!     ", 20);85             else if(nrf_Pipe==1) memcpy(status_buf, "Pipe 1 Send OK!     ", 20);86             else if(nrf_Pipe==2) memcpy(status_buf, "Pipe 2 Send OK!     ", 20);87             else if(nrf_Pipe==3) memcpy(status_buf, "Pipe 3 Send OK!     ", 20);88             else if(nrf_Pipe==4) memcpy(status_buf, "Pipe 4 Send OK!     ", 20);89             else if(nrf_Pipe==5) memcpy(status_buf, "Pipe 5 Send OK!     ", 20);               90         }91         92         SPI_RW_Reg(WRITE_REG1+STATUS, status);         //清除07寄存器標志              93       }        94       EXTI_ClearITPendingBit(EXTI_Line0);             //清除EXTI0上的中斷標志              95   }   96   OSIntExit();           //在os_core.c文件里定義,如果有更高優(yōu)先級的任務(wù)就緒了,則執(zhí)行一次任務(wù)切換     97 }
          串口和無線中斷子程序

          最后說明

          對于純玩軟件的小伙伴,這里涉及的東西有點多,不必細究,看看了解即可。但是對于初學stm32,尤其是還在為stm32控制NRF24L01不通的同學,這個還是挺有用



          關(guān)鍵詞: stm32NRF24L01USART無線通

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();