OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7140|回复: 8

STM32F1串口接收字符串问题

[复制链接]

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2018-11-6
在线时间
14 小时
发表于 2022-12-5 20:21:18 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 BG2DPB 于 2022-12-8 00:20 编辑

论坛的大佬们有没有碰到过这样的一个问题,就是在使用STM32F1的USART1和DMA传输数据时,只要STM32一接收到00数据时,STM32就默认为接收完成了,后面的数据就丢弃了,后面的数据就没办法接收了。我之前碰到过这个问题,是在调Modbus协议的时候,从传感器发过来的数据 只要是有00数据,这个通讯就中断了,后面的数据就接收不到了,一直卡在这里,导致后的传感器数据根本没办法解析。最近是在调上位机和STM32通讯过程中发现这个问题,上位机是Visual Studio编写的,只要是上位机发送00数据时,STM32解析就失败了,饶了一大圈还是回到了刚开始的哪个问题,STM32F1串口一接收到00数据就中断了。小弟没有头绪了(头大),还请各位论坛的大佬们给一点建议。
另外好像串口工作在空闲中断和DMA模式会出现这种情况,在接收中断的情况下好像没有出现这种情况?
usart2.c
//初始化函数
void uart2_init(unsigned long bound)
{
  GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);   
        RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2,ENABLE);  
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

        //USART2_TX   GPIOA.2 = TX
        GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;   
        GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //复用推挽输出   
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
        GPIO_Init(GPIOA,&GPIO_InitStructure);   

  //USART2_RX          GPIOA.3 = RX
        GPIO_InitStructure.GPIO_Pin= GPIO_Pin_3;   
        GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING;  //复用开漏输入   
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        //中断初始化
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;    //抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                               //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);
  //串口2初始化
        USART_InitStructure.USART_BaudRate = bound;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART2, &USART_InitStructure);       //串口1初始化
        USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);        //是能串口DMA接收
//  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能接收中断
//        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//使能空闲中断
        
        DMA_DeInit(DMA1_Channel6);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(USART2->DR);//DMA外设地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&USART2_RX_BUF[0];//DMA接收端地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//设置DMA的传输方向,从外设到内存
        DMA_InitStructure.DMA_BufferSize = USART2_REC_LEN;//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;//DMA1的Channel6
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel6,&DMA_InitStructure);                                                     //DMA1_Channel6 配置
        USART_Cmd(USART2, ENABLE);                      //使能串口2
        DMA_Cmd(DMA1_Channel6,DISABLE);
        MYDMA_Enable();

}
void MYDMA_Enable(void)
{
        DMA_Cmd(DMA1_Channel6,DISABLE);
        DMA_SetCurrDataCounter(DMA1_Channel6,10);//先默认设置成10长度
        DMA_Cmd(DMA1_Channel6, ENABLE);
        
}

main.c
int main(void)
{
        char Modbus_Buff[100];//接受的字符串数组
//        int string_len;//获取字符串的长度
        GPIO_Config();//GPIO初始化
        uart_init(115200);
        uart2_init(9600);
//        TIM2_PWM_Init();
        delay_ms(1000);
        printf("Init_Succeed!\r\n");
        while(1)
        {
                count_i++;
                //该Modbus函数将串口移植到了USART2上面,所以串口1可以用来做调试使用
                if(USART2_RX_BUF[0])
                {
                        delay_ms(10);
                        strcpy(Modbus_Buff, USART2_RX_BUF);//复制字符串保存
                        memset(USART2_RX_BUF,0,10);//清空数组
                        MYDMA_Enable();//开始一次DMA传输
                        modbus(Modbus_Buff,10);
                        Demo_Deal(Receive_Buf);//尝试解析数据
                }
//                if(Receive_Flag == 1)//如果串口2获取到一帧数据
//                {
//                        strcpy(Modbus_Buff, USART2_RX_BUF);//复制字符串保存
//                        string_len = strlen(Modbus_Buff);
//                        modbus(Modbus_Buff,string_len);
//                        Receive_Flag = 0;
//                        Demo_Deal(Receive_Buf);//把接收到的数据发送回去
//                }
                if(count_i<500)  //0.2s
                {
                        GPIO_ResetBits(GPIOC,GPIO_Pin_13);                   //上电点亮LED
//                        printf("A!\r\n");
                }               
                else if((count_i>500)&&(count_i<1000))
                {
                        GPIO_SetBits(GPIOC,GPIO_Pin_13);                   //上电点亮LED
//                        printf("B!\r\n");
                }
                else if(count_i>=1000)
                {
                        count_i=0;
                }
               
               
        }
} Question.png
完整程序详见附件中的压缩包


Question01.zip

6.25 MB, 下载次数: 4

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

821

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3329
金钱
3329
注册时间
2011-11-10
在线时间
207 小时
发表于 2022-12-6 18:44:48 | 显示全部楼层
这是数据解析的问题吧。串口接收中断情况下的代码和DMA时候代码仔细检查一下是否完全一致。只要接收中断正常,DMA也能正常工作。仔细检查代码。
回复

使用道具 举报

11

主题

2103

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4588
金钱
4588
注册时间
2015-1-10
在线时间
574 小时
发表于 2022-12-7 09:08:48 | 显示全部楼层
就算是用空闲中断也不会因为接收到0x00就触发中断,只有在数据帧不连续的情况下才会多次触发空闲中断
回复

使用道具 举报

10

主题

3281

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8206
金钱
8206
注册时间
2020-5-11
在线时间
3700 小时
发表于 2022-12-7 09:24:48 | 显示全部楼层
上代码
回复

使用道具 举报

3

主题

800

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3775
金钱
3775
注册时间
2017-3-7
在线时间
1645 小时
发表于 2022-12-7 10:07:17 | 显示全部楼层
是不是上位机00数据处理有问题,发送时间间隔超过空闲中断周期,不用空闲中断,用定时器试试?
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2018-11-6
在线时间
14 小时
 楼主| 发表于 2022-12-7 11:14:03 | 显示全部楼层
阿侑kevin 发表于 2022-12-7 09:08
就算是用空闲中断也不会因为接收到0x00就触发中断,只有在数据帧不连续的情况下才会多次触发空闲中断

之前传感器发送上来的数据很明显就是一接收到00数据就中断了,后面的数据就不存在数组里了,之前严重怀疑我自己的程序有问题,但是确实是没找到根本的原因。
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2018-11-6
在线时间
14 小时
 楼主| 发表于 2022-12-7 11:16:15 | 显示全部楼层
a5820736 发表于 2022-12-7 10:07
是不是上位机00数据处理有问题,发送时间间隔超过空闲中断周期,不用空闲中断,用定时器试试?

在接收中断的情况下,串口1接收数据 然后通过串口2打印出去是没有这种情况的,一旦要使用空闲中断/DMA接收,就卡在00数据位上了。定时器没试过,回头我再试试,谢谢您给提供了一个思路,回头看下定时器的代码
回复

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
60
金钱
60
注册时间
2018-11-6
在线时间
14 小时
 楼主| 发表于 2022-12-7 11:16:46 | 显示全部楼层

晚上回去打包代码直接上传
回复

使用道具 举报

13

主题

643

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2432
金钱
2432
注册时间
2019-12-28
在线时间
527 小时
发表于 2022-12-7 12:33:22 | 显示全部楼层
帮顶  
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 21:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表