关闭

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

标签: stm32空闲中断DMA接收不定长数据UCOS消息队列wifi转串口
1085人阅读 评论(0) 收藏 举报
分类:

最近做一个中继,一边是基于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;">//↓任务2
void 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 10		
extern 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_RX
TIM1_CH2
TIM3_CH4
TIM3_UP
SPI1_TX
DMA1_Chanel4:
USART1_TX
TIM1_CH4
TIM1_TRIG
TIM1_COM
TIM4_CH2
SPI/I2S2_RX
I2C2_TX
DMA1_Chanel5:
USART1_RX
TIM1_UP
SPI/I2S2_TX
TIM2_CH1
TIM4_CH3
I2C2_RX
DMA1_Chanel6:
USART2_RX
TIM1_CH3
TIM3_CH1
TIM3_TRIG
I2C1_TX
DMA1_Chanel7:
USART2_TX
TIM2_CH2
TIM2_CH4
TIM4_UP
I2C1_RX
DMA2_Chanel1:
SPI/I2S3_RX
TIM5_CH4
TIM5_TRIG
TIM8_CH3
TIM8_UP
DMA2_Chanel2:
SPI/I2S3_TX
TIM5_CH3
TIM5_UP
TIM8_CH4
TIM8_TRIG
TIM8_COM
DMA2_Chanel3:
UART4_RX
TIM6_UP
DAC1
TIM8_CH1
DMA2_Chanel4:
SDIO
TIM5_CH2
TIM7_UP
DAC2
DMA2_Chanel5:
ADC3
UART4_TX
TIM5_CH1
TIM8_CH2



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


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


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




2015、11、20
                                                                                                                                                                                                                                            Themelody

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:130679次
    • 积分:1760
    • 等级:
    • 排名:千里之外
    • 原创:39篇
    • 转载:12篇
    • 译文:0篇
    • 评论:80条
    最新评论