单片机论坛

 找回密码
 立即注册

QQ登录

只需一步快速开始

搜索
查看: 76|回复: 0
打印 上一主题 下一主题
收起左侧

Stm32串口的无阻塞收发调试

[复制链接]
跳转到指定楼层
楼主
无妨 发表于 2019-9-6 18:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Stm32 芯片目前具有一定的用户例程也很多大多数仅仅是 demo的作用往往只注重于功能的实现意思就是说看这个usart 功能这样就可以实现了但应用于一个运行稳定的产品还需要很多技巧

串口应用大概可以说在mcu 应用来说是最广的其主要作用就是收发它在应用中又表现出两种类型客户端 client 和服务端 server通信就是人与人聊天人与人聊天的表现把人分为为收和答者或者说采访者和受访者也可以说主从结构先说客户端通常有两者做法一是无阻塞式一种是有阻塞式前者是发出命令后做一全直量标识记下我前一次发的什么命令然后等待收数据的消息在消息处理过程中根据命令标识来对收到的数据进行相应处理后者有阻塞式做法就是一个函数发出命令后等待收到正确数据并解析在等待的过程中可以用TickCount 做timeout超过一定时间还没收到数据可以退出返回false解决死等的问题因为操作系统有多线程前者可以在主线程行出稳定的通信后者在线程中应用比较多
服务端的做法思想和客户端不一样是受访者要做到有求必答服务端重中之重的还是稳定第一当然收到正确的请求后到应答可以允许有一定的思考时间 我通常是这样做做一全直量用于放接收到的数据接收的地方只管往接收容器里装发现满了就全部倒掉再装其它不用管在主循分解析收到的帧数据做出应答解析过程中对不符合协议的数据可以根据协议做出错误回应或不做任何反应完成后把收容器里的数据清空下面的代码实现了在stm32 的dma 的usart 的收发体现了上述的一些思想我用了systick 实现了超时的概念有说uart 的idle 总线空闲本身就是一个超时我又想例如和一个口吃者聊天用它做超时是不是不太友善 这一点我没做深究
代码中含有485 较的控制一开始是在dma 的中断控制的但总是少两个字节我就在发送的时候多发2 个字节也可以用请读者选择吧

下面是.h 文件输出函数
void USART1_GPIOConfig(void);
void USART1_Config(void);
void USART1_NVICConfig(void);
void USART1_SendString( char* data); // 无阻塞发送址串函数
void USART1_SendData(u8* data,u8 len);// 无阻塞发送函数
下面是.c 文件
#define DMA_USART1_BUFLEN 32 // 保存DMA 看问据传送的长度
u8 USART1_SendBuff[DMA_USART1_BUFLEN];
u8 USART1_TX_Finish=Co_TRUE; // USART 发送完成标志量
u8 USART1_ReceivBuff[DMA_USART1_BUFLEN];
void USART1_GPIOConfig(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; /* 复用推挽输出模式*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; /* 输出最大频率为50MHz */
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 配置USART1 Rx (PA10) */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* 浮帐入模式*/

GPIO_Init(GPIOA, &GPIO_InitStruct);
/// 485 dir
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init( GPIOA, &GPIO_InitStruct);
GPIO_ResetBits( GPIOA, GPIO_Pin_8);// dir
}
void USART1_NVICConfig(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel=DMA1_Channel5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void USART1_Config(void)
{
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStructure;
/* USART and USART2 configured as follow:
- BaudRate = 9600 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled */
USART_InitStruct.USART_BaudRate = 9600;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
USART_ITConfig(USART1,USART_IT_IDLE, ENABLE);// 空闲中断
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
USART_Cmd(USART1, ENABLE);
USART_ClearFlag(USART1,USART_FLAG_TC);///*CPU 的小缺陷串口配置好如果直接Send则
第1 个字节发送不出去?如下语句解决第1 个字节无法正确发送出去的问题*/
////////////////////////////////// 发送dma////////////////////////////////////////////////
DMA_DeInit(DMA1_Channel4); //将DMA 的通道1 寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef*)USART1)->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SendBuff; //DMA 内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输较
DMA_InitStructure.DMA_BufferSize = DMA_USART1_BUFLEN; //DMA 通道的DMA 缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8 位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 数据宽度为8 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA 通道x 拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA 通道x 没有设置为内存到内存传输
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel4,DISABLE);
DMA_ITConfig(DMA1_Channel4,DMA_IT_TE,ENABLE);// 错误中断
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);// 完成中断
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//接收dma///////////////////////////////////////////////
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)(&((USART_TypeDef*)USART1)->DR);
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)USART1_ReceivBuff;
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize=DMA_USART1_BUFLEN;
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority=DMA_Priority_High;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
DMA_Init(DMA1_Channel5,&DMA_InitStructure);
DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);

DMA_ITConfig(DMA1_Channel5,DMA_IT_TE,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA_Cmd(DMA1_Channel5,ENABLE);
}
void DMA1_Channel4_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC4);
DMA_ClearITPendingBit(DMA1_IT_TE4);
DMA_Cmd(DMA1_Channel4,DISABLE);
USART1_TX_Finish=Co_TRUE;
}
void DMA1_Channel5_IRQHandler(void){
DMA_ClearITPendingBit(DMA1_IT_TC5);
DMA_ClearITPendingBit(DMA1_IT_TE5);
DMA_Cmd(DMA1_Channel5,DISABLE);
pc_AppendData(USART1_ReceivBuff,DMA_USART1_BUFLEN);
DMA1_Channel5->CNDTR=DMA_USART1_BUFLEN;// 重装填
DMA_Cmd(DMA1_Channel5,ENABLE);
}
void USART1_IRQHandler(void)
{
u16 alen;
if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET){// 如果为空闲总线中断?
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
DMA_Cmd(DMA1_Channel5,DISABLE);// 关闭DMA, 防止处理其间有数据
alen=DMA_USART1_BUFLEN-DMA_GetCurrDataCounter(DMA1_Channel5);
if(alen>0){
pc_AppendData(USART1_ReceivBuff,alen);
}
DMA_ClearFlag(DMA1_FLAG_GL5|DMA1_FLAG_TC5|DMA1_FLAG_TE5|DMA1_FLAG_HT5);// 清标
志?
DMA1_Channel5->CNDTR=DMA_USART1_BUFLEN;// 重装填?
DMA_Cmd(DMA1_Channel5,ENABLE);// 处理完,重开DMA
//读SR 后读DR 清除Idle
alen=USART1->SR;
alen=USART1->DR;
}
if(USART_GetITStatus(USART1,USART_IT_PE|USART_IT_FE|USART_IT_NE)!=RESET){// 出错
USART_ClearITPendingBit(USART1,USART_IT_PE|USART_IT_FE|USART_IT_NE);
}

//发送中断处理
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET){
USART_ClearITPendingBit(USART1, USART_IT_TC); //清除中断标志
GPIO_ResetBits( GPIOA, GPIO_Pin_8);
}
}
void USART1_SendString(char* data)
{
USART1_SendData((u8*)data,strlen(data));
}
void USART1_SendData(u8* data,u8 len)
{
memcpy(USART1_SendBuff,data,len);
while(USART1_TX_Finish==0);
DMA_Cmd(DMA1_Channel4,DISABLE);
GPIO_SetBits( GPIOA, GPIO_Pin_8);
DMA1_Channel4->CNDTR=len;
USART1_TX_Finish=0;
DMA_Cmd(DMA1_Channel4,ENABLE);
}
上述代码实现了stm32 的串口1 的收发功能应用说明如下
实现windows 操作中的TickCount 方法
U32 sysTickCount;
void SysTick_Handler(void)
{
sysTickCount++;
}
实现接收容器
#define PC_LEN 48
u8 pc_receivdata[IDCPC_LEN]; // 用来乘放接收数据
u8 pc_count=0; // 接收字节数
U32 pc_lastrec; // 最后一次接收的tickcount 值
void pc_AppendData(u8* value,u8 alen){
if((pc_count+alen)>PC_LEN)
pc_count=0;
if(alen<=PC_LEN){
memcpy(&pc_receivdata[pc_count],value,alen);
pc_count+=alen;
pc_lastrec = sysTickCount;
}
}
然后在主循分检测接收数据

u32 tvalue;
if(pc_count>0){
tvalue = sysTickCount - pc_lastrec;
if(tvalue>3){ // 这里3 可以根据systickcount 的频率修改适当可以取20ms
⋯⋯⋯ ..//分析帧数据
USART4_SendData(..); 调用无阻塞发送应答
idcpc_count=0; // 清空容器
}
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51Hei单片机16群 联系QQ:125739409;技术交流QQ群7344883

Powered by 单片机坛网

快速回复 返回顶部 返回列表
ձһhƬձƵ ձƵɫwww ձƵ:ɫ