最近做一个中继,一边是基于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(),用来从嵌入式设备中读取数据,然后存入消息队列
构建任务,每一个任务相当于一个线程。他需要三个必须的东西:身份证(任务管理模块),房子(栈),大脑(代码块)。
首先分别设置优先级和分配栈
/*******************ÉèÖÃÈÎÎñÓÅÏȼ¶*******************/
#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
定义任务
OS_STK task_readfromwifi[TASK_READFROMWIFI_STK_SIZE];
OS_STK task_readfromuart[TASK_READFROMUART_STK_SIZE];
完成准备任务后,再去main内创建并开始任务:
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();
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
//↓任务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);
}
}
MsgQequeTabNum 20,结果硬件中断,单步调试发现,程序都不运行到main的第一句话就直接炸了,后来发现时栈溢出的原因,坑了好久。)
#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];
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);
//
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];
可以接受不定长数组;
并且更加节约资源,不需要你在一个线程内一直在等待接收数据,或者像之前一样用查询的方式去监听;
谁用谁知道!。
之前转的一篇文章已经很详细的给了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和设备串口效果图: