stm32基于Ucos消息队列的空闲中断信息读取储存和发送

来源:互联网 发布:海关数据编码查询 编辑:程序博客网 时间:2024/05/29 14:14

最近做一个中继,一边是基于Wifi的网络,一边是基于串口的嵌入式设备。两者之间通过中继进行通信。

具体结构:


网络设备(手机,pad,PC等等)→→ WIFI网络→→ UART1→→ STM32消息队列→→UART2→→ 嵌入式设备


直连的话会遇到以下 2  个问题:

1.当WIFI网络或嵌入式设备发送来的数据过多,接收后来不及发送给另一边。数据会丢失

2.数据不定长


所以用了下面 2 个解决方法:

1.基于Ucos的消息队列:将接收到的数据立刻存入队列中,达到一个缓冲的目的。保证接收到数据都发送出去,当然缓冲时的数据不能多余消息队列的开的大小。(消息队列开的过大会造成硬件中断,所有程序无法执行。)

2.串口空闲中断,当串口idle中断时,通过控制DMA通道的使能,来接收数据。节约CPU资源。稳定可靠。


PCB截图:




开始码代码:

STM32的Ucos移植就不说了,网上一抓一大把。


首先搭建任务,很明显这个项目里需要两个Task。

一个是Task_ReadFromWifi(),用来从wifi网络中读取数据,然后存入消息队列

另一个是Task_ReadFromUart(),用来从嵌入式设备中读取数据,然后存入消息队列


构建任务,每一个任务相当于一个线程。他需要三个必须的东西:身份证(任务管理模块),房子(栈),大脑(代码块)。

首先分别设置优先级和分配栈

<span style="font-size:18px;"><span style="font-size:18px;">/*******************ÉèÖÃÈÎÎñÓÅÏȼ¶*******************/#define TASK_READFROMWIFI_PRIO 5#define TASK_READFROMUART_PRIO 6//#define TASK_TESTLED_PRIO 6/************ÉèÖÃÕ»´óС£¨µ¥Î»Îª OS_STK £©************/#define TASK_READFROMWIFI_STK_SIZE 256#define TASK_READFROMUART_STK_SIZE 256//#define TASK_TESTLED_STK_SIZE 20</span></span>

定义任务

<span style="font-size:18px;">OS_STK task_readfromwifi[TASK_READFROMWIFI_STK_SIZE];OS_STK task_readfromuart[TASK_READFROMUART_STK_SIZE];</span>


完成准备任务后,再去main内创建并开始任务:

<span style="font-size:18px;">  BSP_Init();  OSInit();  OSTaskCreate(Task_ReadFromWifi,(void *)0, &task_readfromwifi[TASK_READFROMWIFI_STK_SIZE-1], TASK_READFROMWIFI_PRIO);OSTaskCreate(Task_ReadFromUart,(void *)0, &task_readfromuart[TASK_READFROMUART_STK_SIZE-1], TASK_READFROMUART_PRIO);OSStart();</span>


然后在APP.c内准备好给两个任务的大脑装东西,一开始写的时候直接留空白就好了,我这里直接把我的代码贴上来:

<span style="font-size:18px;">void Task_ReadFromWifi(void *p_arg){uint8_t *s; INT8U err; while (1) {      s = OSQPend(QSem,0,&err);      if(err==OS_NO_ERR)      {       printf("\r\nMsgFromPhone   =\r\n       ");       Puts_UART2(s);//´®¿Ú2·¢Ë͸øPad       }      OSTimeDly(20);   }}//↑任务1</span>
<span style="font-size:18px;">//↓任务2void Task_ReadFromUart(void *p_arg){uint8_t *s;INT8U err;while(1){s=OSQPend(QSem2,0,&err);if(err==OS_NO_ERR){printf("\r\nMsgFromPC   =\r\n        ");Puts_UART2(s);Puts_UART1(s);//´®¿Ú1·¢Ë͸øµçÄÔ}OSTimeDly(20);}}</span>

搭建好基本的后,准备消息队列:(调试过程中,出于贪心,我想把数列开的大一点,所以#define了

MsgQequeTabNum 20,结果硬件中断,单步调试发现,程序都不运行到main的第一句话就直接炸了,后来发现时栈溢出的原因,坑了好久。


<span style="font-size:18px;">#define MSG_QUEUE_TABNUM 10extern OS_EVENT *QSem;extern OS_MEM   *PartitionPt;extern uint8_t  Partition[MSG_QUEUE_TABNUM][400];extern  void *MsgQeueTb[MSG_QUEUE_TABNUM];extern OS_EVENT *QSem2;extern OS_MEM *PartitionPt2;extern uint8_t  Partition2[MSG_QUEUE_TABNUM][400];extern  void *MsgQeueTb2[MSG_QUEUE_TABNUM];</span>


然后再Main内:

<span style="font-size:18px;">QSem = OSQCreate(&MsgQeueTb[0],MSG_QUEUE_TABNUM); PartitionPt=OSMemCreate(Partition,MSG_QUEUE_TABNUM,400,&err);QSem2 = OSQCreate(&MsgQeueTb2[0],MSG_QUEUE_TABNUM); PartitionPt2=OSMemCreate(Partition2,MSG_QUEUE_TABNUM,400,&err);</span>


因为任务代码是写在app.c内,所以要用到的消息队列的变量需要继续定义一下

<span style="font-size:18px;">//OS_EVENT *QSem;void *MsgQeueTb[MSG_QUEUE_TABNUM];OS_MEM   *PartitionPt;uint8_t  Partition[MSG_QUEUE_TABNUM][400];// OS_EVENT *QSem2; void *MsgQeueTb2[MSG_QUEUE_TABNUM]; OS_MEM *PartitionPt2; uint8_t Partition2[MSG_QUEUE_TABNUM][400];</span>


接下来只需要配置串口的空闲中断就可以了,空闲中断有很多优点:

可以接受不定长数组;

并且更加节约资源,不需要你在一个线程内一直在等待接收数据,或者像之前一样用查询的方式去监听;

谁用谁知道!。



之前转的一篇文章已经很详细的给了stm32串口空闲中断的代码和介绍了,

里面有各个模块的配置 GPIO DMA UART NVIC

在此就不多说了。

可移步:

http://blog.csdn.net/lxk7280/article/details/49700663



注意一点就是DMA的不同频道对应的外设是不同的,不要弄错了,整理了一下,贴上来:

DMA1 Channel1:ADC1  TIM2_CH3  TIM4_CH1  DMA1 
DMA1 Channel2:USART3_TX  TIM1_CH1  TIM2_UP  TIM3_CH3  SPI1_RX
DMA1_Chanel3:USART3_RXTIM1_CH2TIM3_CH4TIM3_UPSPI1_TX
DMA1_Chanel4:USART1_TXTIM1_CH4TIM1_TRIGTIM1_COMTIM4_CH2SPI/I2S2_RXI2C2_TX
DMA1_Chanel5:USART1_RXTIM1_UPSPI/I2S2_TXTIM2_CH1TIM4_CH3I2C2_RX
DMA1_Chanel6:USART2_RXTIM1_CH3TIM3_CH1TIM3_TRIGI2C1_TX
DMA1_Chanel7:USART2_TXTIM2_CH2TIM2_CH4TIM4_UPI2C1_RX
DMA2_Chanel1:SPI/I2S3_RXTIM5_CH4TIM5_TRIGTIM8_CH3TIM8_UP
DMA2_Chanel2:SPI/I2S3_TXTIM5_CH3TIM5_UPTIM8_CH4TIM8_TRIGTIM8_COM
DMA2_Chanel3:UART4_RXTIM6_UPDAC1TIM8_CH1
DMA2_Chanel4:SDIOTIM5_CH2TIM7_UPDAC2
DMA2_Chanel5:ADC3UART4_TXTIM5_CH1TIM8_CH2



果然不丢失数据了诶,实际测试以10ms的间隔同时互相发送数据,完全没有问题。我们有理由相信1ms的间隔也是没问题的,`(*∩_∩*)′,不过这个项目的中继也不会接受那么高频率的数据的。。。


WIFI网络的手机和设备串口效果图:


WIFI网络的PC和设备串口效果图:




2015、11、20
                                                                                                                                                                                                                                            Themelody

0 0
原创粉丝点击