OpenEdv-开源电子网

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

RS485 使用 USART1 始终无法成功

[复制链接]

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
发表于 2019-4-11 23:34:43 | 显示全部楼层 |阅读模式
5金钱
手上的板子将485接在了USART1上。我尝试修改代码但是始终无法正确通信。debug都进不了USART1_IRQHandler方法。在站里也搜索了好久始终没能解决问题。求大佬解救。

具体情况:
STM32F103VBT6
485芯片SP3082EE,管脚RX接PA10,TX接PA9,中间两个接PA8。

下面是485init 方法[mw_shl_code=c,true]void RS485_Init(u32 bound)
{
        GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                                 //PD8端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;        //PA9
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

        RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,DISABLE);//停止复位

       
#ifdef EN_USART1_RX                          //如果使能了接收
        USART_InitStructure.USART_BaudRate = bound;//波特率设置
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
        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(USART1, &USART_InitStructure); ; //初始化串口
  
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口2中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级2级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
        NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
   
  USART_Cmd(USART1, ENABLE);                    //使能串口

#endif

  RS485_TX_EN=0;                        //默认为接收模式
}
[/mw_shl_code]


USART1_IRQHandler 方法写在同一文件中
[mw_shl_code=c,true]void USART1_IRQHandler(void)
{
        u8 res;            

        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
        {         
                                  
                res =USART_ReceiveData(USART1);         //读取接收到的数据
                if(RS485_RX_CNT<64)
                {
                        RS485_RX_BUF[RS485_RX_CNT]=res;                //记录接收到的值
                        RS485_RX_CNT++;                                                //接收数据增加1
                }
        }                                                                                           
} [/mw_shl_code]

NVIC_PriorityGroupConfig 写在main方法中
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);


目前情况:
代码从485的例子来的,在开发板上可以跑通,换了芯片信息后重新编译的。修改了485中的代码。
由于例子代码中usart.x中使用了USART1,所以我先把usart.x给删了,然后发现程序都没办法debug,具体表现是debug后无法进入main方法,查询后发现好像和其中的printf,半主机模式相关。
然后就把usart.x部分的代码保留,将原来使用到USART1的部分都替换成了USART2。可以正常debug了,但是USART1_IRQHandler都不会走。

使用usart1做485通信的时候需要注意哪些东西?usart1用于485通信了,那原来usart.x中的相关代码怎么修改?

自学STM32一段时间了,好不容易将实例搞完,可以用开发板做出自己想要的效果了,想着换个板子试试。没想到问题好多,自学这玩意真的难。




最佳答案

查看完整内容[请看2#楼]

初始化: #include "sys.h" #include "rs485.h" #include "delay.h" #include "usart.h" ////////////////////////////////////////////////////////////////////////////////// /** @maven10注意这里@maven10 使能引脚PA4 串口1 TXD PA9 RXD PA10 **/ ////////////////////////////////////////////////////////////////////////////////// #ifdef EN_USART1_RX //如果使能了接 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-11 23:34:44 | 显示全部楼层
初始化:

#include "sys.h"                    
#include "rs485.h"         
#include "delay.h"
#include "usart.h"

//////////////////////////////////////////////////////////////////////////////////         
/**
@maven10注意这里@maven10 使能引脚PA4
串口1  TXD PA9
       RXD PA10
                         
**/
//////////////////////////////////////////////////////////////////////////////////


#ifdef EN_USART1_RX           //如果使能了接收


//接收缓存区        
u8 RS485_RX_BUF[64];          //接收缓冲,最大64个字节.
//接收到的数据长度
u8 RS485_RX_CNT=0;                     


void USART1_IRQHandler(void)
{
        u8 res;            

        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
        {         
                                  
                res =USART_ReceiveData(USART1);         //读取接收到的数据
                if(RS485_RX_CNT<64)
                {
                        RS485_RX_BUF[RS485_RX_CNT]=res;                //记录接收到的值
                        RS485_RX_CNT++;                                                //接收数据增加1
                }
        }
        printf("uasrt  is ready \r\n");

}


#endif                                                                                 
//初始化IO 串口1
//pclk1CLK1时钟频率(Mhz)
//bound:波特率          
void RS485_Init(u32 bound)
{  
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA时钟    1111.....
               
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                 //PA4端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        //USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9

  //USART1_RX          GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  


        RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,DISABLE);//停止复位

       
#ifdef EN_USART1_RX                          //如果使能了接收

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器

   //USART 初始化设置

        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        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(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1
       
        printf("uart_init is ready\r\n");

#endif

  RS485_TX_EN=0;                        //默认为接收模式

}

//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void RS485_Send_Data(u8 *buf,u8 len)
{
        u8 t;
        RS485_TX_EN=1;                        //设置为发送模式
          for(t=0;t<len;t++)                //循环发送数据
        {       
               
                  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);          
                  USART_SendData(USART1,buf[t]);
//                while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);          
//                USART_SendData(USART2,buf[t]);
        }         
printf("RS485_Send_Data\r\n");
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);               
        RS485_RX_CNT=0;          
        RS485_TX_EN=0;                                //设置为接收模式       
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf,u8 *len)
{
        u8 rxlen=RS485_RX_CNT;
        u8 i=0;
        *len=0;                                //默认为0
        delay_ms(10);                //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
        if(rxlen==RS485_RX_CNT&&rxlen)//接收到了数据,且接收完成了
        {
                for(i=0;i<rxlen;i++)
                {
                        buf=RS485_RX_BUF;       
                }               
                *len=RS485_RX_CNT;        //记录本次数据长度
                RS485_RX_CNT=0;                //清零
        }
}



主函数:
#define test485  1
int main(void)
{
        u8 key;
        u8 i=0,t=0;
        u8 cnt=0;
        u8 rs485buf[5];
       
       
/************************************** init **********************************************/       
  delay_init();            //延时函数初始化       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        //uart_init(9600);
       
        led_init();      //LED初始化
        W25QXX_Init();//W25QXX初始化,包括了SPI2的初始化
        FSMC_SRAM_Init();                        //初始化外部SRAM  
  Touch_Init();        //初始化触摸屏
        LCD_Init();
        RS485_Init(9600);
/************************************* end init *******************************************/
       
        //flash_test(1); //测试flash:1是写flash,0是读flash
        //fsmc_sram_test(0);//测试SRAM:1是测试容量,0是读取数据
       
        LCD_ShowString(30,50,200,16,16,"STM32 Test");
        LCD_ShowString(30,70,200,16,16,"RS485 TEST");       
        LCD_ShowString(30,90,200,16,16,"XXXXXXXxxx");
        LCD_ShowString(30,110,200,16,16,"2019/4/151");       
        //LCD_ShowString(30,130,200,16,16,"KEY0:Send");        //显示提示信息               

        POINT_COLOR=BLUE;//设置字体为蓝色          
        LCD_ShowString(30,150,200,16,16,"Count:");                        //显示当前计数值       
        LCD_ShowString(30,170,200,16,16,"Send Data:");                //提示发送的数据       
        LCD_ShowString(30,210,200,16,16,"Receive Data:");        //提示接收到的数据       

#if test485
        for(i=0;i<5;i++)
        {
                rs485buf=cnt+i;//填充发送缓冲区
                LCD_ShowxNum(30+i*32,190,rs485buf,3,16,0X80);        //显示数据
        }
        RS485_Send_Data(rs485buf,5);//发送5个字节
       
#else
//        RS485_Receive_Data(rs485buf,&key);
//        if(key>5)key=5;//最大是5个数据.
//                         for(i=0;i<key;i++)LCD_ShowxNum(30+i*32,230,rs485buf,3,16,0X80);        //显示数据
       
       
#endif
       
        while(1)
        {
   //malloc_test();
         //touch_test();
   //LCD_test();
                RS485_Receive_Data(rs485buf,&key);
                if(key)//接收到有数据
                {
                        //if(key>5)key=5;//最大是5个数据.
                        for(i=0;i<key;i++)LCD_ShowxNum(30+i*32,230,rs485buf,3,16,0X80);        //显示数据
                }
                t++;
                delay_ms(10);
                if(t==20)
                {
                        //led_show();//提示系统正在运行       
                        t=0;
                        cnt++;
                        LCD_ShowxNum(30+48,150,cnt,3,16,0X80);        //显示数据
                        LED =!LED;
                }                  
               
        }
}

















回复

使用道具 举报

31

主题

2183

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
14433
金钱
14433
注册时间
2018-8-3
在线时间
1157 小时
发表于 2019-4-12 09:27:44 | 显示全部楼层
RX 接 PA9    TX接 PA10 试下
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-12 10:11:06 | 显示全部楼层
好巧....我也在调试串口1的485通信
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2019-4-9
在线时间
7 小时
发表于 2019-4-12 10:21:33 | 显示全部楼层
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,DISABLE);//停止复位

你把串口时钟关了干嘛?
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2019-4-9
在线时间
7 小时
发表于 2019-4-12 10:25:35 | 显示全部楼层
还有中断优先级,主优先级和副优先级是有取值氛围限制的
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
 楼主| 发表于 2019-4-12 13:53:22 | 显示全部楼层
otto1230 发表于 2019-4-12 10:21
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
    RCC_APB2PeriphResetCmd(RCC ...

这个代码是例子里的,应该不是关,而是复位的动作,先复位在停止复位 应该是为了刷新什么东西吧。
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
 楼主| 发表于 2019-4-12 13:54:29 | 显示全部楼层
otto1230 发表于 2019-4-12 10:25
还有中断优先级,主优先级和副优先级是有取值氛围限制的

嗯这个我知道的  我设置的 VIC_PriorityGroupConfig(NVIC_PriorityGroup_2); group 2  那应该两个值得取值范围都是0-3,应该不存在问题。
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
 楼主| 发表于 2019-4-12 13:55:48 | 显示全部楼层
天涯海QxkJX 发表于 2019-4-12 10:11
好巧....我也在调试串口1的485通信

哎搞不定,搞出来麻烦给我参考参考。。谢谢啦
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
 楼主| 发表于 2019-4-12 13:57:21 | 显示全部楼层
翼行园子 发表于 2019-4-12 09:27
RX 接 PA9    TX接 PA10 试下

板子,接法应该是没问题的。因为我这里有现成的hex,是可以让485成功的。但是没有源码。
而且是固定的板子,也不太好修改。
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2019-4-9
在线时间
7 小时
发表于 2019-4-12 14:18:26 | 显示全部楼层
maven10 发表于 2019-4-12 13:53
这个代码是例子里的,应该不是关,而是复位的动作,先复位在停止复位 应该是为了刷新什么东西吧。

你不管是不是例程里的,你把串口时钟打开又关闭,串口怎么能正常工作
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-12 14:23:50 | 显示全部楼层
otto1230 发表于 2019-4-12 14:18
你不管是不是例程里的,你把串口时钟打开又关闭,串口怎么能正常工作

那个不是时钟,只是复位过程
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-12 14:24:18 | 显示全部楼层
maven10 发表于 2019-4-12 13:55
哎搞不定,搞出来麻烦给我参考参考。。谢谢啦

你搞出来也记得分享一下哦
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2019-4-9
在线时间
7 小时
发表于 2019-4-12 14:56:26 | 显示全部楼层
天涯海QxkJX 发表于 2019-4-12 14:23
那个不是时钟,只是复位过程

...好吧,我看错了
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2019-4-9
在线时间
7 小时
发表于 2019-4-12 14:58:41 | 显示全部楼层
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
你把这个打开试试
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-12 15:21:14 | 显示全部楼层
usart的printf可以保留,不影响。注意电路接口哦,我调了一早上发现通信异常是因为接口松了........
回复

使用道具 举报

16

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
327
金钱
327
注册时间
2019-3-11
在线时间
50 小时
发表于 2019-4-12 15:23:05 | 显示全部楼层
保留printf函数 ,利用串口调试助手,能打印信息说明串口正常工作,串口初始化没有问题。如果485通信还有问题,就要多检查硬件电路了。还搞不出来再@我吧
回复

使用道具 举报

6

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2018-1-22
在线时间
21 小时
发表于 2019-4-15 10:05:54 | 显示全部楼层
天涯海QxkJX 发表于 2019-4-12 15:23
保留printf函数 ,利用串口调试助手,能打印信息说明串口正常工作,串口初始化没有问题。如果485通信还有问 ...

你好,我485遇到的问题是:使用485与传感器通信,然后将传感器数据存储进sd卡里。我移植是实验25 485实验和FATFS测试工程的代码。移植之后我也仔细的检查了代码。串口2可以发送数据,就是接受不到数据。但是使用试验25 485实验代码可以正常通信。然后我使用了串口3和RS232转485模块。串口也能发送数据,就是接受不了数据。求大神指导。使用的是战舰板子。感谢
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-3-29
在线时间
10 小时
 楼主| 发表于 2019-4-15 17:12:55 | 显示全部楼层
接线 将其连接到usart2上后同样也不行。我去研究具体电路了。虽然我的问题还是不能解决,但是天涯海QxkJX 的回答应该可以解决这个帖子的问题。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-22 11:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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