前语
一般进行长途监控时,2.4G无线通讯是充任长途数据传输的一种办法。这时就需要在现场部分具有无线数据发送设备,而在上位机部分咱们一般只需串口,所以将并重到的数据送到电脑里又要在上位机端规划一个数据接纳的适配器。这儿依据stm32别离规划了现场部分和适配器部分,这儿只是根本通讯功用完结的解说,一些杂乱的技能比方加密、牢靠等要依据详细的应用来规划~
整体阐明
这儿选用stm32作为MCU,选用nRF24L01作为2.4G通讯模块。其间适配器中只是选用了USART和NRF24L01两个首要部分,担任将下位机经过2.4G发送过来的数据经过串口发送给上位机,或许将上位机的经过串口传来的数据经过2.4G发送给下位机来完结长途监控(没有选用uc-os操作体系,也没有界面,要用串口和上位机相连);其间下位机比较杂乱,咱们一般下位机是一个集成的体系,包括从各种传感器搜集数据、向各种类型的驱动电路发送操控指令、将数据输给打印机或显现器、和无线通讯或有线通讯设备进行相互通讯来完结数据传输等,这儿的下位机比较简单:选用uc-os实时操作体系+uc-gui担任界面显现,外接7寸TFT液晶显现屏,和适配器相似也包括USART和NRF24L01通讯部分,可是咱们有了操作体系和可视化交互界面,所以也有点不同,接下来开端介绍。
适配器部分
这儿介绍的流程是以main函数为基准,广度拓展知识点,最终main函数说完,整个工程的细节也就大致能了解了~
1 int main(void){2 uint8_t a=0;//LED凹凸电压操控3 /* System Clocks Configuration */4 RCC_Configuration(); //体系时钟设置 5 /*嵌套向量中止操控器 6 阐明晰USART1抢占优先级等级0(最多1位) ,和子优先级等级0(最多7位) */ 7 NVIC_Configuration(); //中止源装备8 /*对操控LED指示灯的IO口进行了初始化,将端口装备为推挽上拉输出,口线速度为50Mhz。PA9,PA10端口复用为串口1的TX,RX。9 在装备某个口线时,首要应对它地点的端口的时钟进行使能。不然无法装备成功,咱们用到了端口B, 因而要对这个端口的时钟10 进行使能,一起咱们用到复用IO口功用用于装备串口。因而还要使能AFIO(复用功用IO)时钟。*/11 GPIO_Configuration(); //端口初始化12 SPI2_NRF24L01_Init(); //SPI2及NRF24L01接口初始化 13 USART_Config(USART1); //串口1初始化14 /*NRF24L01设置为接纳形式*/15 RX_Mode(); 16 17 while (1)18 {19 if(usart_rec_flag==1) //判别是否收到一帧有用数据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++)//发送字符串30 {31 USART_SendChar(USART1,TxBufferUSART[i]);32 // Delay(0x0ff00);33 }34 }35 }36 }
第4行RCC初始化首要是体系时钟和外设时钟装备,这儿留意要使能RCC_APB2Periph_USART1,其时忘了使能这个成果串口出现异常,我还以为是初始化和中止向量什么的弄错了呢,浪费了很长时刻。
1 /*--2 体系时钟装备为72MHZ+外设时钟装备*/ 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行中止向量初始化设置,首要是设置串口接纳中止和NRF24L01中止的,这样设置好了之后当串口中止被触发时其对应的中止子程序将被碑文(这个科班的大约都知道这儿就不多说了),所以咱们就要在stm32f10x_it.c里完结他们各自的中止子程序了(这个一会再详细介绍,咱们先把整个结构了解下)。别的说一句,这儿的的优先级组将影响主优先级和子优先级数量详细请参阅stm32f10X_的固件库的NVIC.
1 void NVIC_Configuration(void){2 /* 结构声明*/3 NVIC_InitTypeDef NVIC_InitStructure;4 EXTI_InitTypeDef EXTI_InitStructure; 5 6 /* 优先级组 1 */ 7 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 8 9 /* Enable the USART1 Interrupt */10 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置串口1中止11 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 012 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级为013 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能14 NVIC_Init(&NVIC_InitStructure); 15 16 17 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //NRF24L01 中止呼应18 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 019 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级为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; //下降沿触发28 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能29 EXTI_Init(&EXTI_InitStructure); 30 }
第11行的GPIO初始化,首要是对通用IO口的特点设置和初始化,这儿必定要对串口所需的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();首要是驱动NRF24L01的接口初始化,咱们NRF24L01选用的是SPI通讯,所以这儿免不了SPI的设置和相关操作了,不过幸亏都封装好了~像曾经在51上做SPI就得自己模仿SPI,没有示波器调试起来甚是坑~此外这儿我现已把NRF24L01的整个驱动都封装在NRF24L01.c这个文件里了,当想用的时分只需在中止向量里设置其间断接纳函数,并在it.c里完结其接纳函数;一般主函数里用到的是其初始化函数SPI2_NRF24L01_Init();和RX_Mode();,当在进程中想使用NRF24L01向外发数据时只需调用函数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 * 功 能:将保存在接纳缓存区的32字节的数据经过NRF24L01+发送出去4 * 进口参数:data_buffer 待发送数据5 Nb_bytes 待发送数据长度6 * 出口参数:无7 * 说 明:数据小于32,把有用数据外的空间用0填满8 * 调用办法: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); //设置情况存放器初始化16 SPI_RW_Reg(0xe1,0); //铲除TX FIFO存放器17 SPI_RW_Reg(0xe2,0); //铲除RX FIFO存放器18 TX_Mode(); //设置为发送形式19 delay_ms(1);20 if(Nb_bytes<32){ //当接纳到的USB虚拟串口数据小于32,把有用数据外的空间用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); //发送32字节的缓存区数据到NRF24L0125 MODE_CE(1); //坚持10us以上,将数据发送出去 26 }
第13行是USART初始化,包括波特率、数据位、中止位等~
1 void USART_Config(USART_TypeDef* USARTx){2 USART_InitStructure.USART_BaudRate = 9600; //速率9600bps3 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位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; //收发形式8 9 /* Configure USART1 */10 USART_Init(USARTx, &USART_InitStructure); //装备串口参数函数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); //使能发送缓冲空中止 16 17 /* Enable the USART1 */18 USART_Cmd(USART1, ENABLE); 19 }
相同的相似于NRF24L01一旦初始化之后,其数据接纳一般选用中止办法、数据发送一般选用直接发送的办法。所以在中止向量里也要设置,也要在it.c中完结其接纳中止子函数。其发送直接调用stm32f10的固件库函数(这儿我稍加封装了下):其实便是发送一个data之后要监听是否发送完结才干进行下次发送~
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循环,不断进行监听看是否有串口接纳标志方位1或许无线模块接纳标志方位1,如果有标明相应的有数据从该通道传送过来。当是从串口传来的数据标明数据是从上位机发送来的数据,而且想把该数据经过2.4G发送出去,所以这儿调用:NRF_Send_Data(TxBufferRF,sizeof(TxBufferRF));将数据发送出去;当数据是从2.4G通道中传过来的,标明数据是从下位机传送过来的想给上位机,所以调用串口发送函数将数据发送给上位机:USART_SendChar(USART1,TxBufferUSART[i]);
看了上图适配器端的数据交换进程就了解了串口中止和无线中止大致要干的事了,这儿我就不多介绍,看看下面的代码就了解了(在stm32f10x_it.c中),要再次提示的是无论是串口仍是无线其接纳都是选用中止,而发送选用循环直接发送,他们的中止和中止向量有关并要在stm32f10x_it.c里完结相应的中止子程序~
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 中止服务程序11 {12 unsigned int i;13 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判别读存放器是否非空14 { 15 16 RxBufferUSART[RxCounter1++] = USART_ReceiveData(USART1); //将读存放器的数据缓存到接纳缓冲区里17 18 if(RxBufferUSART[RxCounter1-2]==0x0d&&RxBufferUSART[RxCounter1-1]==0x0a) //判别完毕标志是否是0x0d 0x0a19 {20 for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i]; //将接纳缓冲器的数据转到发送缓冲区,预备转发21 usart_rec_flag=1; //接纳成功标志22 TxBufferRF[RxCounter1]=0; //发送缓冲区完毕符 23 TxCounter1=RxCounter1;24 RxCounter1=0;25 }26 }27 28 if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //这段是为了防止STM32 USART 第一个字节发不出去的BUG 29 { 30 USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //制止发缓冲器空中止, 31 } 32 } 33 /*******************************************************************************34 * Function Name : EXTI0 中止函数35 * Description : NRF24L01中止服务程序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) //判别是否产生了EXTI0中止44 {45 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0){ //判别是否是PA0线变低 46 status=SPI_Read(READ_REG1+STATUS); // 读取情况存放其来判别数据接纳情况 47 if(status & 0x40) // 判别是否接纳到数据 48 { 49 //GPIO_ResetBits(GPIOB, GPIO_Pin_5); 50 SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH); //从接纳缓冲区里读出数据51 for(i=0; i<32; i++)TxBufferUSART[i] = rx_buf[i]; //向USB 端点1的缓冲区里放置数据 52 rf_rec_flag=1;53 }54 else if((status &0x10)>0){ //发射到达最大复发次数 55 SPI_RW_Reg(0xe1,0); //铲除发送缓冲区 56 RX_Mode(); //进入接纳形式 57 }58 else if((status &0x20)>0){ //发射后收到应对 59 GPIO_SetBits(GPIOB, GPIO_Pin_5); 60 SPI_RW_Reg(0xe1,0); //铲除发送缓冲区 61 RX_Mode(); //进入接纳形式 62 }63 SPI_RW_Reg(WRITE_REG1+STATUS, status); //铲除07存放器标志64 } 65 EXTI_ClearITPendingBit(EXTI_Line0); //铲除EXTI0上的中止标志 66 } 67 }
串口和无线接纳中止子程序
下位机部分
上面说过一般具有长途通讯才能的嵌入式体系其下位机部分往往要干很多事,这儿咱们选用stm32作为MCU并搭载uc-OS实时操作体系担任使命调度,一起选用7寸TFT彩屏和uc-GUI规划可视化人机交互界面。其间使命包括主使命、界面使命和角度使命,主使命担任树立其他使命,界面使命中将包括整个人机交互界面的界面改写逻辑,角度使命担任获取角度方位数据获取~
这儿咱们仍是得从main函数先说起:首要在main函数中进行相关初始化,然后树立主使命并发动uc-OS内核;接着在主使命中调用App_TaskCreate();别离树立界面使命和角度使命(如下每个使命的树立相似,要给出指向使命代码的指针、使命碑文时传递给使命的参数的指针,分配给这个使命的栈信息,使命优先级等)。这样当使命树立好之后,其碑文权就由操作体系调度了~
1 static void App_TaskCreate(void)2 {3 /* 树立用户界面使命 */4 OSTaskCreateExt(AppTaskUserIF, //指向使命代码的指针5 (void *)0, //使命开端碑文时,传递给使命的参数的指针6 (OS_STK *)&AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE-1], //分配给使命的仓库的栈顶指针 从顶向下递减7 APP_TASK_USER_IF_PRIO, //分配给使命的优先级8 APP_TASK_USER_IF_PRIO, //预备给今后版别的特别标识符,在现行版别同使命优先级9 (OS_STK *)&AppTaskUserIFStk[0], //指向使命仓库栈底的指针,用于仓库的查验10 APP_TASK_USER_IF_STK_SIZE, //指定仓库的容量,用于仓库的查验11 (void *)0, //指向用户附加的数据域的指针,用来扩展使命的使命操控块12 OS_TASK_OPT_STK_CHKOS_TASK_OPT_STK_CLR); //选项,指定是否答应仓库查验,是否将仓库清0,使命是否要13 //进行浮点运算等等。14 15 /* 树立角度驱动使命 */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 }
这儿以界面使命为例:咱们咱们在树立界面使命时现已指定其使命代码指针AppTaskUserIF,所以这儿来写其对应的函数(也便是说这儿是界面使命的进口)。从下面的代码能够看出进入界面使命时首要对uc-GUI进行初始化,然后进入死循环不断碑文Fun()函数(有人会疑问:这儿while死循环不就只能死在这儿吗?怎样碑文其他使命呢?,这便是具有操作体系和不具有操作体系的不同啦~尽管这儿是while死循环,可是当OS要把CPU占有权分给其他使命时就会把当时碑文的使命的信息压入其对应的栈空间,当再次要把CPU分配给该使命时,则把栈里保存的前次碑文的情况拿出来持续碑文,然后完结抢占与多使命的效果!)
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函数:尽管代码有点长,可是很好了解,其中心思路便是树立整个界面并对界面中的每个控件进行相关设置一起取得其句柄,在最终又进入了while死循环,在循环中不断检测2.4G是否接受到数据(和适配器端相似也是中止子程序中收数据然后置接纳标志为1的),然后依据从2.4G收到的数据来改写文本显现区;下面一个if判别speed_change_flag是否有用来向串口发送相应的数据。那么咱们的问题又来了:这个speed_change_flag是在哪里被改动的呢?这个咱们就要参看窗口回调函数了!这儿的窗口回调函数是窗口动作呼应函数(就像安卓开发里的按钮监听或MFC里的按钮点击事情等),一旦窗口里的控件有相应的触发动作就会调用该函数,并把事情类型封装在WM_MESSAGE里传过来,在该函数里对该音讯进行解析并作出相应的动作即可(十分像Win32!!!我置疑做这个uc-GUI的人有copy微软的嫌疑,♪(^∇^*)随意猜想,如有雷同,纯属巧合)。这样咱们就很简单找到send按钮的监听用于将数据经过NRF24L01发送出去的相关操作,也就了解了滑动条监听用来改动speed1~5.上面说了这么多,少了介绍整个界面是怎样树立的了~其实整个窗体的布局都要放在一个结构体里,然后在fun()函数里调用hWin = GUI_CreateDialogBox(aDialogCreate, GUI_COUNTOF(aDialogCreate), _cbCallback, 0, 0, 0);依据界说的窗口资源和回调函数进行窗体的树立~这样咱们就满意地了解了stm32依据uc-OS并搭载uc-GUI的运转逻辑啦!
1 void Fun(void) { 2 GUI_CURSOR_Show(); //翻开鼠标图形显现 3 4 /* 树立对话框时,包括了资源列表,资源数目, 而且指定了用于动作呼应的回调函数 */5 hWin = GUI_CreateDialogBox(aDialogCreate, GUI_COUNTOF(aDialogCreate), _cbCallback, 0, 0, 0);6 7 FRAMEWIN_SetFont(hWin, &GUI_FontComic18B_1); //对话框字体设置 8 FRAMEWIN_SetClientColor(hWin, GUI_BLACK); //对话框的窗体色彩是黑色9 memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32); //将长度为32字节的发送字符串拷贝到发送缓冲区,10 memcpy(rx_buf, "", 32); //将接纳缓存区清空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项目(情况字符文本框)的句柄 19 /* 设置文本框字体 */20 TEXT_SetFont(text1,pFont); //设置对话框里文本框Send Text Area的字体21 TEXT_SetFont(text2,pFont); //设置对话框里文本框Receive Text Area的字体22 TEXT_SetFont(text3,pFont18); //设置对话框里文本框2M BPS的字体23 TEXT_SetFont(text4,pFont18); //设置对话框里文本框1M BPS的字体24 TEXT_SetFont(text6,pFont18); //设置对话框里文本框250K BPS的字体25 TEXT_SetFont(text5,pFont); //设置对话框里情况字符文本框的字体26 /* 设置文本框色彩 */27 TEXT_SetTextColor(text1,GUI_GREEN); //设置对话框里文本框Send Text Area的字体色彩28 TEXT_SetTextColor(text2,GUI_GREEN ); //设置对话框里文本框Receive Text Area的字体色彩29 TEXT_SetTextColor(text3,GUI_YELLOW); //设置对话框里文本框2M BPS的字体色彩30 TEXT_SetTextColor(text4,GUI_YELLOW); //设置对话框里文本框1M BPS的字体色彩31 TEXT_SetTextColor(text6,GUI_YELLOW); //设置对话框里文本框250K BPS的字体色彩32 TEXT_SetTextColor(text5,GUI_YELLOW); //设置对话框里情况字符文本框的字体色彩33 TEXT_SetBkColor(text5,GUI_BLUE); //设置对话框里情况字符文本框的布景色彩34 35 /* 修改框相关 */36 edit1 = WM_GetDialogItem(hWin, GUI_ID_EDIT1); //取得对话框里GUI_ID_EDIT1项目(修改框 发送字符串显现区)的句柄37 EDIT_SetFont(edit1,pFont18); //设置对话框里修改框 发送字符串显现区的字体38 EDIT_SetText(edit1,(const char *)tx_buf); //设置对话框里修改框 发送字符串显现区的字符串39 edit2 = WM_GetDialogItem(hWin, GUI_ID_EDIT2); //取得对话框里GUI_ID_EDIT2项目(修改框 接纳字符串显现区)的句柄40 EDIT_SetFont(edit2,pFont18); //设置对话框里修改框 接纳字符串显现区的字体41 EDIT_SetText(edit2,(const char *)rx_buf); //设置对话框里修改框 接纳字符串显现区的字符串42 43 /* 按钮相关 */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); //设置对话框里按键SEND的字体47 BUTTON_SetFont(bt[1],pFont); //设置对话框里按键CLEAR的字体48 BUTTON_SetTextColor(bt[0],0,GUI_WHITE); //设置对话框里按键SEND未被按下的字体色彩49 BUTTON_SetTextColor(bt[1],0,GUI_WHITE); //设置对话框里按键CLEAR未被按下的字体色彩50 51 /* List相关 */ 52 nrf_Pipe=0; //NRF24L01初始发射通道设置为053 list1 = WM_GetDialogItem(hWin, GUI_ID_LISTBOX0); //取得对话框里GUI_ID_LISTBOX0项目(列表框-通道挑选)的句柄 54 LISTBOX_SetText(list1, _apListBox); //设置对话框里列表框-通道挑选里的条目55 LISTBOX_SetFont(list1,pFont18); //设置对话框里列表框-通道挑选的字体56 LISTBOX_SetSel(list1,nrf_Pipe); //设置对话框里列表框-通道挑选的焦点挑选57 SCROLLBAR_CreateAttached(list1, SCROLLBAR_CF_VERTICAL); //设置对话框里列表框-通道挑选的卷动方向为下拉 58 59 /* Radio按钮相关 */ 60 rd0 = WM_GetDialogItem(hWin, GUI_ID_RADIO0); //取得对话框里GUI_ID_RADIO0项目(点选框-速率挑选)的句柄61 nrf_baud=0; //NRF24L01速率 初始为2MPS62 RADIO_SetValue(rd0,0); //设置对话框里点选框-速率挑选的焦点挑选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 /* 设置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 /* 设置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 /* 设置文本框字体 */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 /* 设置文本框色彩 */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接纳到有用数据107 EDIT_SetText(edit2,(const char *)rx_buf); //将接纳缓冲区的字符写入到接纳字符修改框内108 TEXT_SetText(text5,(const char *)status_buf); //将情况文本缓冲区的字符写入到情况文本框内109 Rx_Succ=0; 110 // for(i=0;i
Fun()
1 /****************************************************************************2 * 名 称:static void _cbCallback(WM_MESSAGE * pMsg)3 * 功 能:ucgui回调函数,是作为对话框动作呼应的函数4 * 进口参数:无5 * 出口参数:无6 * 说 明:7 * 调用办法:8 ****************************************************************************/ 9 static void _cbCallback(WM_MESSAGE * pMsg) {10 int NCode, Id;11 switch (pMsg->MsgId) {12 case WM_NOTIFY_PARENT: //告诉父窗口有事情在窗口部件上产生13 Id = WM_GetId(pMsg->hWinSrc); //取得对话框窗口里产生事情的部件的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); //清空情况文本缓冲区 19 memcpy(rx_buf, "", 32); //清空接纳文本缓冲区 20 TEXT_SetText(text5,(const char *)status_buf); //清空情况文本框 21 EDIT_SetText(edit2,(const char *)rx_buf); //清空接纳字符修改框22 memcpy(tx_buf, "", 32); //清空发送文本缓冲区23 NRF24L01_TXBUF(tx_buf,32); //将发送字符缓冲区的字符经过NRF24L01发送出去 24 } 25 else if (Id == GUI_ID_BUTTON0) { //按键SEND 被松开26 memcpy(tx_buf, "1234567890abcdefghij!@#$%^&*()-=", 32); //将32字节的文本拷贝到发送文本缓冲区27 memcpy(rx_buf, "", 32); //清空接纳文本缓冲区 28 memcpy(status_buf, "", 20); //清空情况文本缓冲区 29 EDIT_SetText(edit2,(const char *)rx_buf); //清空接纳字符修改框 30 NRF24L01_TXBUF(tx_buf,32); //将发送字符缓冲区的字符经过NRF24L01发送出去31 memcpy(tx_buf, "", 32); //清空发送文本缓冲区32 TEXT_SetText(text5,(const char *)status_buf); //清空情况文本框 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 }
窗口回调函数
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 //树立滑块对应的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函数中的BSP_Init();函数,该函数负相关硬件的初始化设置(中文意思是板级支撑包初始化函数,咱们uc-OS能够并不只限于stm32单片机,所以这儿要依据不同渠道进行相应的设置)。该函数坐落bsp.c函数中,其效果相当于将曾经咱们在main函数中进行的相关硬件初始化独自拿出来封装成一个函数罢了~可是,串口和无线对应的中止接纳程序却有点不一样,咱们这儿是操作体系,所以在每个中止子程序前要调用OS_ENTER_CRITICAL();保存当时的大局中止标志,然后OSIntNesting++;中止嵌套深度加1,最终调用OS_EXIT_CRIT%&&&&&%AL();康复大局中止标志进入正常的中止处理,此外在中止呼应函数最终要调用OSIntExit(); 检测如果有更高优先级的使命安排妥当了,则碑文一次使命切换。
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(); //保存大局中止标志,关总中止 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); //将读存放器的数据缓存到接纳缓冲区里19 if(RxBufferUSART[RxCounter1-2]==0x0d&&RxBufferUSART[RxCounter1-1]==0x0a) //判别完毕标志是否是0x0d 0x0a20 {21 for(i=0; i< RxCounter1; i++) TxBufferRF[i] = RxBufferUSART[i]; //将接纳缓冲器的数据转到发送缓冲区,预备转发22 usart_rec_flag=1; //接纳成功标志23 TxBufferRF[RxCounter1]=0; //发送缓冲区完毕符 24 TxCounter1=RxCounter1;25 RxCounter1=0;26 }27 }28 if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //这段是为了防止STM32 USART 第一个字节发不出去的BUG 29 { 30 USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //制止发缓冲器空中止, 31 } 32 OSIntExit(); //在os_core.c文件里界说,如果有更高优先级的使命安排妥当了,则碑文一次使命切换 33 }34 /////////////////////////////35 void EXTI0_IRQHandler(void)36 { 37 unsigned char status,i;38 OS_CPU_SR cpu_sr;39 OS_ENTER_CRITICAL(); //保存大局中止标志,关总中止 Tell uC/OS-II that we are starting an ISR40 OSIntNesting++;41 OS_EXIT_CRITICAL(); //康复大局中止标志 42 43 if(EXTI_GetITStatus(EXTI_Line0) != RESET) //判别是否产生了EXTI0中止44 {45 if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0){ //判别是否是PA0线变低 46 status=SPI_Read(READ_REG1+STATUS); // 读取情况存放其来判别数据接纳情况 47 if(status & 0x40) // 判别是否接纳到数据 48 { 49 SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH); //从接纳缓冲区里读出数据 50 for(i=0; i<32; i++){ //向USB 端点1的缓冲区里放置数据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; //读取数据完结标志59 /* 依据读出的接纳通道号,将相应信息写入情况文本缓冲区 */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){ //发射到达最大复发次数 68 SPI_RW_Reg(0xe1,0); //铲除发送缓冲区 69 RX_Mode(); //进入接纳形式 70 Rx_Succ=1; 71 /* 依据发送通道,将相应信息写入情况文本缓冲区 */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){ //发射后收到应对 80 SPI_RW_Reg(0xe1,0); //铲除发送缓冲区 81 RX_Mode(); //进入接纳形式82 Rx_Succ=1;83 /* 依据发送通道,将相应信息写入情况文本缓冲区 */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文件里界说,如果有更高优先级的使命安排妥当了,则碑文一次使命切换 97 }
串口和无线中止子程序
最终阐明
关于纯玩软件的小伙伴,这儿触及的东西有点多,不用细究,看看了解即可。可是关于初学stm32,尤其是还在为stm32操控NRF24L01不通的同学,这个仍是挺有用