新聞中心

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

stm32 NRF24L01+USART搞定有線和無(wú)線通信

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

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

本文引用地址:http://m.butianyuan.cn/article/201611/318440.htm

總體說(shuō)明

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

適配器部分

這里介紹的流程是以main函數(shù)為基準(zhǔn),廣度拓寬知識(shí)點(diǎn),最后main函數(shù)說(shuō)完,整個(gè)工程的細(xì)節(jié)也就大致能了解了~

1 int main(void){2   uint8_t a=0;//LED高低電壓控制3   /* System Clocks Configuration */4   RCC_Configuration();                                              //系統(tǒng)時(shí)鐘設(shè)置    5   /*嵌套向量中斷控制器 6       說(shuō)明了USART1搶占優(yōu)先級(jí)級(jí)別0(最多1位) ,和子優(yōu)先級(jí)級(jí)別0(最多7位) */ 7   NVIC_Configuration();                                              //中斷源配置8   /*對(duì)控制LED指示燈的IO口進(jìn)行了初始化,將端口配置為推挽上拉輸出,口線速度為50Mhz。PA9,PA10端口復(fù)用為串口1的TX,RX。9   在配置某個(gè)口線時(shí),首先應(yīng)對(duì)它所在的端口的時(shí)鐘進(jìn)行使能。否則無(wú)法配置成功,由于用到了端口B, 因此要對(duì)這個(gè)端口的時(shí)鐘10   進(jìn)行使能,同時(shí)由于用到復(fù)用IO口功能用于配置串口。因此還要使能AFIO(復(fù)用功能IO)時(shí)鐘。*/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í)鐘和外設(shè)時(shí)鐘配置,這里注意要使能RCC_APB2Periph_USART1,當(dāng)時(shí)忘了使能這個(gè)結(jié)果串口出現(xiàn)異常,我還以為是初始化和中斷向量什么的弄錯(cuò)了呢,浪費(fèi)了很長(zhǎng)時(shí)間。

1 /*--2 系統(tǒng)時(shí)鐘配置為72MHZ+外設(shè)時(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è)置好了之后當(dāng)串口中斷被觸發(fā)時(shí)其對(duì)應(yīng)的中斷子程序?qū)⒈粓?zhí)行(這個(gè)科班的大概都知道這里就不多說(shuō)了),所以我們就要在stm32f10x_it.c里實(shí)現(xiàn)他們各自的中斷子程序了(這個(gè)一會(huì)再詳細(xì)介紹,咱們先把整個(gè)框架了解下)。另外說(shuō)一句,這里的的優(yōu)先級(jí)組將影響主優(yōu)先級(jí)和子優(yōu)先級(jí)數(shù)量具體請(qǐng)參考stm32f10X_的固件庫(kù)的NVIC.

1 void NVIC_Configuration(void){2  /*  結(jié)構(gòu)聲明*/3   NVIC_InitTypeDef NVIC_InitStructure;4   EXTI_InitTypeDef EXTI_InitStructure;        5   6   /* 優(yōu)先級(jí)組 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)先級(jí) 012   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                //子優(yōu)先級(jí)為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)先級(jí) 019   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                //子優(yōu)先級(jí)為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初始化,主要是對(duì)通用IO口的屬性設(shè)置和初始化,這里一定要對(duì)串口所需的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;             //復(fù)用推挽輸出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;        //復(fù)用開漏輸入13   GPIO_Init(GPIOA, &GPIO_InitStructure);                      //A端口 14 }

第12行的SPI2_NRF24L01_Init();主要是驅(qū)動(dòng)NRF24L01的接口初始化,因?yàn)镹RF24L01采用的是SPI通信,所以這里免不了SPI的設(shè)置和相關(guān)操作了,不過(guò)幸好都封裝好了~像以前在51上做SPI就得自己模擬SPI,沒有示波器調(diào)試起來(lái)甚是坑~此外這里我已經(jīng)把NRF24L01的整個(gè)驅(qū)動(dòng)都封裝在NRF24L01.c這個(gè)文件里了,當(dāng)想用的時(shí)候只要在中斷向量里設(shè)置其中斷接收函數(shù),并在it.c里實(shí)現(xiàn)其接收函數(shù);一般主函數(shù)里用到的是其初始化函數(shù)SPI2_NRF24L01_Init();和RX_Mode();,當(dāng)在過(guò)程中想利用NRF24L01向外發(fā)數(shù)據(jù)時(shí)只要調(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ù)通過(guò)NRF24L01+發(fā)送出去4 * 入口參數(shù):data_buffer   待發(fā)送數(shù)據(jù)5             Nb_bytes      待發(fā)送數(shù)據(jù)長(zhǎng)度6 * 出口參數(shù):無(wú)7 * 說(shuō)    明:數(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){                         //當(dāng)接收到的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;                //無(wú)校驗(yàn)位6   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   //無(wú)硬件流控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中實(shí)現(xiàn)其接收中斷子函數(shù)。其發(fā)送直接調(diào)用stm32f10的固件庫(kù)函數(shù)(這里我稍加封裝了下):其實(shí)就是發(fā)送一個(gè)data之后要監(jiān)聽是否發(fā)送完成才能進(jìn)行下次發(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 }

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

看了上圖適配器端的數(shù)據(jù)交換過(guò)程就明白了串口中斷和無(wú)線中斷大致要干的事了,這里我就不多介紹,看看下面的代碼就明白了(在stm32f10x_it.c中),要再次提醒的是無(wú)論是串口還是無(wú)線其接收都是采用中斷,而發(fā)送采用循環(huán)直接發(fā)送,他們的中斷和中斷向量有關(guān)并要在stm32f10x_it.c里實(shí)現(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é)束標(biāo)志是否是0x0d 0x0a19     {20       for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i];          //將接收緩沖器的數(shù)據(jù)轉(zhuǎn)到發(fā)送緩沖區(qū),準(zhǔn)備轉(zhuǎn)發(fā)21       usart_rec_flag=1;                                                             //接收成功標(biāo)志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 第一個(gè)字節(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)寄存其來(lá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 端點(diǎn)1的緩沖區(qū)里放置數(shù)據(jù)      52                 rf_rec_flag=1;53             }54             else if((status &0x10)>0){                     //發(fā)射達(dá)到最大復(fù)發(fā)次數(shù)                55                 SPI_RW_Reg(0xe1,0);                          //清除發(fā)送緩沖區(qū)                  56                 RX_Mode();                                 //進(jìn)入接收模式                   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();                                 //進(jìn)入接收模式                   62             }63             SPI_RW_Reg(WRITE_REG1+STATUS, status);         //清除07寄存器標(biāo)志64         }        65         EXTI_ClearITPendingBit(EXTI_Line0);             //清除EXTI0上的中斷標(biāo)志              66     } 67 }
串口和無(wú)線接收中斷子程序

下位機(jī)部分

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

這里我們還是得從main函數(shù)先說(shuō)起:首先在main函數(shù)中進(jìn)行相關(guān)初始化,然后建立主任務(wù)并啟動(dòng)uc-OS內(nèi)核;接著在主任務(wù)中調(diào)用App_TaskCreate();分別建立界面任務(wù)和觸摸任務(wù)(如下每個(gè)任務(wù)的建立類似,要給出指向任務(wù)代碼的指針、任務(wù)執(zhí)行時(shí)傳遞給任務(wù)的參數(shù)的指針,分配給這個(gè)任務(wù)的棧信息,任務(wù)優(yōu)先級(jí)等)。這樣當(dāng)任務(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í)行時(shí),傳遞給任務(wù)的參數(shù)的指針6                        (OS_STK *)&AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE-1],  //分配給任務(wù)的堆棧的棧頂指針   從頂向下遞減7                     APP_TASK_USER_IF_PRIO,                                       //分配給任務(wù)的優(yōu)先級(jí)8                     APP_TASK_USER_IF_PRIO,                                       //預(yù)備給以后版本的特殊標(biāo)識(shí)符,在現(xiàn)行版本同任務(wù)優(yōu)先級(jí)9                     (OS_STK *)&AppTaskUserIFStk[0],                               //指向任務(wù)堆棧棧底的指針,用于堆棧的檢驗(yàn)10                     APP_TASK_USER_IF_STK_SIZE,                                    //指定堆棧的容量,用于堆棧的檢驗(yàn)11                     (void *)0,                                                    //指向用戶附加的數(shù)據(jù)域的指針,用來(lái)擴(kuò)展任務(wù)的任務(wù)控制塊12                     OS_TASK_OPT_STK_CHKOS_TASK_OPT_STK_CLR);                    //選項(xiàng),指定是否允許堆棧檢驗(yàn),是否將堆棧清0,任務(wù)是否要13                                                                                 //進(jìn)行浮點(diǎn)運(yùn)算等等。14                     15    /* 建立觸摸驅(qū)動(dòng)任務(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ù)為例:因?yàn)槲覀冊(cè)诮⒔缑嫒蝿?wù)時(shí)已經(jīng)指定其任務(wù)代碼指針AppTaskUserIF,所以這里來(lái)寫其對(duì)應(yīng)的函數(shù)(也就是說(shuō)這里是界面任務(wù)的入口)。從下面的代碼可以看出進(jìn)入界面任務(wù)時(shí)首先對(duì)uc-GUI進(jìn)行初始化,然后進(jìn)入死循環(huán)不斷執(zhí)行Fun()函數(shù)(有人會(huì)疑惑:這里while死循環(huán)不就只能死在這里嗎?怎么執(zhí)行其他任務(wù)呢?,這就是具有操作系統(tǒng)和不具有操作系統(tǒng)的不同啦~雖然這里是while死循環(huán),但是當(dāng)OS要把CPU占有權(quán)分給其他任務(wù)時(shí)就會(huì)把當(dāng)前執(zhí)行的任務(wù)的信息壓入其對(duì)應(yīng)的??臻g,當(dāng)再次要把CPU分配給該任務(wù)時(shí),則把棧里保存的上次執(zhí)行的情況拿出來(lái)繼續(xù)執(zhí)行,從而實(shí)現(xiàn)搶占與多任務(wù)的效果?。?/p>

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

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



1 void Fun(void) {   2   GUI_CURSOR_Show();                                        //打開鼠標(biāo)圖形顯示  3   4   /* 建立對(duì)話框時(shí),包含了資源列表,資源數(shù)目, 并且指定了用于動(dòng)作響應(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);                  //對(duì)話框字體設(shè)置 8   FRAMEWIN_SetClientColor(hWin, GUI_BLACK);                      //對(duì)話框的窗體顏色是黑色9   memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32);   //將長(zhǎng)度為32字節(jié)的發(fā)送字符串拷貝到發(fā)送緩沖區(qū),10   memcpy(rx_buf, "", 32);                                    //將接收緩存區(qū)清空11  12   /* 獲得文本框句柄 */        13   text1 = WM_GetDialogItem(hWin, GUI_ID_TEXT0);                //獲得對(duì)話框里GUI_ID_TEXT0項(xiàng)目(文本框Send Text Area)的句柄14   text2 = WM_GetDialogItem(hWin, GUI_ID_TEXT1);                //獲得對(duì)話框里GUI_ID_TEXT1項(xiàng)目(文本框Receive Text Area)的句柄15   text3 = WM_GetDialogItem(hWin, GUI_ID_TEXT2);                //獲得對(duì)話框里GUI_ID_TEXT2項(xiàng)目(文本框2M BPS)的句柄16   text4 = WM_GetDialogItem(hWin, GUI_ID_TEXT3);                //獲得對(duì)話框里GUI_ID_TEXT3項(xiàng)目(文本框1M BPS)的句柄17   text6 = WM_GetDialogItem(hWin, GUI_ID_TEXT5);                //獲得對(duì)話框里GUI_ID_TEXT5項(xiàng)目(文本框250K BPS)的句柄18   text5 = WM_GetDialogItem(hWin, GUI_ID_TEXT4);                //獲得對(duì)話框里GUI_ID_TEXT4項(xiàng)目(狀態(tài)字符文本框)的句柄  19   /* 設(shè)置文本框字體 */20   TEXT_SetFont(text1,pFont);                                //設(shè)置對(duì)話框里文本框Send Text Area的字體21   TEXT_SetFont(text2,pFont);                                //設(shè)置對(duì)話框里文本框Receive Text Area的字體22   TEXT_SetFont(text3,pFont18);                                //設(shè)置對(duì)話框里文本框2M BPS的字體23   TEXT_SetFont(text4,pFont18);                                //設(shè)置對(duì)話框里文本框1M BPS的字體24   TEXT_SetFont(text6,pFont18);                                //設(shè)置對(duì)話框里文本框250K BPS的字體25   TEXT_SetFont(text5,pFont);                                //設(shè)置對(duì)話框里狀態(tài)字符文本框的字體26   /* 設(shè)置文本框顏色 */27   TEXT_SetTextColor(text1,GUI_GREEN);                        //設(shè)置對(duì)話框里文本框Send Text Area的字體顏色28   TEXT_SetTextColor(text2,GUI_GREEN );                        //設(shè)置對(duì)話框里文本框Receive Text Area的字體顏色29   TEXT_SetTextColor(text3,GUI_YELLOW);                        //設(shè)置對(duì)話框里文本框2M BPS的字體顏色30   TEXT_SetTextColor(text4,GUI_YELLOW);                        //設(shè)置對(duì)話框里文本框1M BPS的字體顏色31   TEXT_SetTextColor(text6,GUI_YELLOW);                       //設(shè)置對(duì)話框里文本框250K BPS的字體顏色32   TEXT_SetTextColor(text5,GUI_YELLOW);                        //設(shè)置對(duì)話框里狀態(tài)字符文本框的字體顏色33   TEXT_SetBkColor(text5,GUI_BLUE);                            //設(shè)置對(duì)話框里狀態(tài)字符文本框的背景顏色34 35   /* 編輯框相關(guān) */36   edit1 = WM_GetDialogItem(hWin, GUI_ID_EDIT1);                //獲得對(duì)話框里GUI_ID_EDIT1項(xiàng)目(編輯框 發(fā)送字符串顯示區(qū))的句柄37   EDIT_SetFont(edit1,pFont18);                                //設(shè)置對(duì)話框里編輯框 發(fā)送字符串顯示區(qū)的字體38   EDIT_SetText(edit1,(const char *)tx_buf);                    //設(shè)置對(duì)話框里編輯框 發(fā)送字符串顯示區(qū)的字符串39   edit2 = WM_GetDialogItem(hWin, GUI_ID_EDIT2);                //獲得對(duì)話框里GUI_ID_EDIT2項(xiàng)目(編輯框 接收字符串顯示區(qū))的句柄40   EDIT_SetFont(edit2,pFont18);                                //設(shè)置對(duì)話框里編輯框 接收字符串顯示區(qū)的字體41   EDIT_SetText(edit2,(const char *)rx_buf);                    //設(shè)置對(duì)話框里編輯框 接收字符串顯示區(qū)的字符串42 43   /* 按鈕相關(guān) */44   bt[0]=WM_GetDialogItem(hWin,GUI_ID_BUTTON0);                //獲得對(duì)話框里GUI_ID_BUTTON0項(xiàng)目(按鍵SEND)的句柄45   bt[1]=WM_GetDialogItem(hWin, GUI_ID_BUTTON2);                //獲得對(duì)話框里GUI_ID_BUTTON2項(xiàng)目(按鍵CLEAR)的句柄46   BUTTON_SetFont(bt[0],pFont);                                //設(shè)置對(duì)話框里按鍵SEND的字體47   BUTTON_SetFont(bt[1],pFont);                                //設(shè)置對(duì)話框里按鍵CLEAR的字體48   BUTTON_SetTextColor(bt[0],0,GUI_WHITE);                     //設(shè)置對(duì)話框里按鍵SEND未被按下的字體顏色49   BUTTON_SetTextColor(bt[1],0,GUI_WHITE);                    //設(shè)置對(duì)話框里按鍵CLEAR未被按下的字體顏色50 51   /* List相關(guān) */            52   nrf_Pipe=0;                                                //NRF24L01初始發(fā)射通道設(shè)置為053   list1 = WM_GetDialogItem(hWin, GUI_ID_LISTBOX0);            //獲得對(duì)話框里GUI_ID_LISTBOX0項(xiàng)目(列表框-通道選擇)的句柄     54   LISTBOX_SetText(list1, _apListBox);                        //設(shè)置對(duì)話框里列表框-通道選擇里的條目55   LISTBOX_SetFont(list1,pFont18);                            //設(shè)置對(duì)話框里列表框-通道選擇的字體56   LISTBOX_SetSel(list1,nrf_Pipe);                            //設(shè)置對(duì)話框里列表框-通道選擇的焦點(diǎn)選擇57   SCROLLBAR_CreateAttached(list1, SCROLLBAR_CF_VERTICAL);    //設(shè)置對(duì)話框里列表框-通道選擇的卷動(dòng)方向?yàn)橄吕?       58 59   /* Radio按鈕相關(guān) */        60   rd0 = WM_GetDialogItem(hWin, GUI_ID_RADIO0);                //獲得對(duì)話框里GUI_ID_RADIO0項(xiàng)目(點(diǎn)選框-速率選擇)的句柄61   nrf_baud=0;                                                //NRF24L01速率 初始為2MPS62   RADIO_SetValue(rd0,0);                                    //設(shè)置對(duì)話框里點(diǎn)選框-速率選擇的焦點(diǎn)選擇63   RX_Mode();                                                //NRF24L01進(jìn)入接收模式 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){                                            //當(dāng)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ù),是作為對(duì)話框動(dòng)作響應(yīng)的函數(shù)4 * 入口參數(shù):無(wú)5 * 出口參數(shù):無(wú)6 * 說(shuō)    明: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);            //獲得對(duì)話框窗口里發(fā)生事件的部件的ID14       NCode = pMsg->Data.v;                       //通知代碼15       switch (NCode) {16         case WM_NOTIFICATION_RELEASED:            //窗體部件動(dòng)作被釋放             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ū)的字符通過(guò)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ū)的字符通過(guò)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無(wú)線速率點(diǎn)選框點(diǎn)選動(dòng)作完成35               nrf_baud= RADIO_GetValue(rd0);        //獲得速率表示值36             RX_Mode();                            //進(jìn)入接收模式            37           }38           else if (Id == GUI_ID_LISTBOX0){      //NRF24L01無(wú)線通道選擇動(dòng)作39             nrf_Pipe= LISTBOX_GetSel(list1);    //獲得NRF24LL01無(wú)線通道表示值             40             RX_Mode();                           //進(jìn)入接收模式     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);                        //默認(rèn)程序來(lái)處理消息133       break;134   }135 }
窗口回調(diào)函數(shù)
1 /* 定義了對(duì)話框資源列表 */2 static const GUI_WIDGET_CREATE_INFO aDialogCreate[] = {3   //建立窗體, 大小是800X480  原點(diǎn)在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控件,起點(diǎn)是窗體的X,X,大小XXY  文字左對(duì)齊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   //建立滑塊對(duì)應(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 };

還要回過(guò)頭說(shuō)說(shuō)我們的USART和NRF24L01,他們的初始化要看main函數(shù)中的BSP_Init();函數(shù),該函數(shù)負(fù)相關(guān)硬件的初始化設(shè)置(中文意思是板級(jí)支持包初始化函數(shù),因?yàn)閡c-OS可以并不只限于stm32單片機(jī),所以這里要根據(jù)不同平臺(tái)進(jìn)行相應(yīng)的設(shè)置)。該函數(shù)位于bsp.c函數(shù)中,其作用相當(dāng)于將以前我們?cè)趍ain函數(shù)中進(jìn)行的相關(guān)硬件初始化單獨(dú)拿出來(lái)封裝成一個(gè)函數(shù)而已~但是,串口和無(wú)線對(duì)應(yīng)的中斷接收程序卻有點(diǎn)不一樣,因?yàn)檫@里是操作系統(tǒng),所以在每個(gè)中斷子程序前要調(diào)用OS_ENTER_CRITICAL();保存當(dāng)前的全局中斷標(biāo)志,然后OSIntNesting++;中斷嵌套深度加1,最后調(diào)用OS_EXIT_CRITICAL();恢復(fù)全局中斷標(biāo)志進(jìn)入正常的中斷處理,此外在中斷響應(yīng)函數(shù)最后要調(diào)用OSIntExit(); 檢測(cè)如果有更高優(yōu)先級(jí)的任務(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();  //保存全局中斷標(biāo)志,關(guān)總中斷 Tell uC/OS-II that we are starting an ISR13     OSIntNesting++;14     OS_EXIT_CRITICAL();      //恢復(fù)全局中斷曛?        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é)束標(biāo)志是否是0x0d 0x0a20         {21             for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i];          //將接收緩沖器的數(shù)據(jù)轉(zhuǎn)到發(fā)送緩沖區(qū),準(zhǔn)備轉(zhuǎn)發(fā)22             usart_rec_flag=1;                                                             //接收成功標(biāo)志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 第一個(gè)字節(jié)發(fā)不出去的BUG 29     { 30         USART_ITConfig(USART1, USART_IT_TXE, DISABLE);                         //禁止發(fā)緩沖器空中斷, 31     }    32     OSIntExit();           //在os_core.c文件里定義,如果有更高優(yōu)先級(jí)的任務(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();  //保存全局中斷標(biāo)志,關(guān)總中斷 Tell uC/OS-II that we are starting an ISR40   OSIntNesting++;41   OS_EXIT_CRITICAL();      //恢復(fù)全局中斷標(biāo)志             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)寄存其來(lá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 端點(diǎn)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;                      //讀出是在哪個(gè)通道接收的56             }57             else nrf_Pipe_r=0;                     58             Rx_Succ=1;            //讀取數(shù)據(jù)完成標(biāo)志59             /* 根據(jù)讀出的接收通道號(hào),將相應(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ā)射達(dá)到最大復(fù)發(fā)次數(shù)                68             SPI_RW_Reg(0xe1,0);                          //清除發(fā)送緩沖區(qū)                  69             RX_Mode();                                 //進(jìn)入接收模式                                 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();                                 //進(jìn)入接收模式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寄存器標(biāo)志              93       }        94       EXTI_ClearITPendingBit(EXTI_Line0);             //清除EXTI0上的中斷標(biāo)志              95   }   96   OSIntExit();           //在os_core.c文件里定義,如果有更高優(yōu)先級(jí)的任務(wù)就緒了,則執(zhí)行一次任務(wù)切換     97 }
串口和無(wú)線中斷子程序

最后說(shuō)明

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



評(píng)論


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

關(guān)閉