第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字节的缓存区数据到NRF24L01
25 MODE_CE(1); //保持10us以上,将数据发送出去
26 }
第13行是USART初始化,包括波特率、数据位、停止位等~
1 void USART_Config(USART_TypeDef* USARTx){
2 USART_InitStructure.USART_BaudRate = 9600; //速率9600bps
3 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);

看了上图适配器端的数据交换过程就明白了串口中断和无线中断大致要干的事了,这里我就不多介绍,看看下面的代码就明白了(在stm32f10x_it.c中),要再次提醒的是无论是串口还是无线其接收都是采用中断,而发送采用循环直接发送,他们的中断和中断向量有关并要在stm32f10x_it.c里实现相应的中断子程序~
串口和无线接收中断子程序
下位机部分
上面说过一般具有远程通信能力的嵌入式系统其下位机部分往往要干很多事,这里我们采用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_CHK|OS_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_CHK|OS_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的运行逻辑啦!

Fun()

窗口回调函数
1 /* 定义了对话框资源列表 */
2 static const GUI_WIDGET_CREATE_INFO aDialogCreate[] = {
3 //建立窗体, 大小是800X480 原点在0,0
4 { 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 //建立滑块对应的text
32 { 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_CRITICAL();恢复全局中断标志进入正常的中断处理,此外在中断响应函数最后要调用OSIntExit(); 检测如果有更高优先级的任务就绪了,则执行一次任务切换。

串口和无线中断子程序
最后说明
对于纯玩软件的小伙伴,这里涉及的东西有点多,不必细究,看看了解即可。但是对于初学stm32,尤其是还在为stm32控制NRF24L01不通的同学,这个还是挺有用滴~下面有工程的链接,里面有些注释不规范,一切以我博客里说的为准哦~
第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字节的缓存区数据到NRF24L01
25 MODE_CE(1); //保持10us以上,将数据发送出去
26 }
第13行是USART初始化,包括波特率、数据位、停止位等~
1 void USART_Config(USART_TypeDef* USARTx){
2 USART_InitStructure.USART_BaudRate = 9600; //速率9600bps
3 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);

看了上图适配器端的数据交换过程就明白了串口中断和无线中断大致要干的事了,这里我就不多介绍,看看下面的代码就明白了(在stm32f10x_it.c中),要再次提醒的是无论是串口还是无线其接收都是采用中断,而发送采用循环直接发送,他们的中断和中断向量有关并要在stm32f10x_it.c里实现相应的中断子程序~
串口和无线接收中断子程序
下位机部分
上面说过一般具有远程通信能力的嵌入式系统其下位机部分往往要干很多事,这里我们采用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_CHK|OS_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_CHK|OS_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的运行逻辑啦!

Fun()

窗口回调函数
1 /* 定义了对话框资源列表 */
2 static const GUI_WIDGET_CREATE_INFO aDialogCreate[] = {
3 //建立窗体, 大小是800X480 原点在0,0
4 { 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 //建立滑块对应的text
32 { 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_CRITICAL();恢复全局中断标志进入正常的中断处理,此外在中断响应函数最后要调用OSIntExit(); 检测如果有更高优先级的任务就绪了,则执行一次任务切换。

串口和无线中断子程序
最后说明
对于纯玩软件的小伙伴,这里涉及的东西有点多,不必细究,看看了解即可。但是对于初学stm32,尤其是还在为stm32控制NRF24L01不通的同学,这个还是挺有用滴~下面有工程的链接,里面有些注释不规范,一切以我博客里说的为准哦~
举报