stm32 NRF24L01+USART搞定有線和無(wú)線通信
一般進(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://2s4d.com/article/201611/318440.htm總體說(shuō)明
這里采用stm32作為MCU,采用nRF24L01作為2.4G通信模塊。其中適配器中僅僅采用了USART和NRF24L01兩個(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)控(沒(méi)有采用uc-os操作系統(tǒng),也沒(méi)有界面,要用串口和上位機(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)開(kā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ù)用開(kāi)漏輸入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,沒(méi)有示波器調(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)聽(tīng)是否發(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)聽(tīng)看是否有串口接收標(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 }
下位機(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ù)開(kāi)始執(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)寫(xiě)其對(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ù)的效果!)
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ù)(就像安卓開(kāi)發(fā)里的按鈕監(jiān)聽(tīng)或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)聽(tīng)用于將數(shù)據(jù)通過(guò)NRF24L01發(fā)送出去的相關(guān)操作,也就明白了滑動(dòng)條監(jiān)聽(tīng)用來(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(); //打開(kāi)鼠標(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ū)的字符寫(xiě)入到接收字符編輯框內(nèi)108 TEXT_SetText(text5,(const char *)status_buf); //將狀態(tài)文本緩沖區(qū)的字符寫(xiě)入到狀態(tài)文本框內(nèi)109 Rx_Succ=0; 110 // for(i=0;i
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被松開(kāi)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 被松開(kāi)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 }
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)信息寫(xiě)入狀態(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)信息寫(xiě)入狀態(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)信息寫(xiě)入狀態(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 }
最后說(shuō)明
對(duì)于純玩軟件的小伙伴,這里涉及的東西有點(diǎn)多,不必細(xì)究,看看了解即可。但是對(duì)于初學(xué)stm32,尤其是還在為stm32控制NRF24L01不通的同學(xué),這個(gè)還是挺有用
評(píng)論