RS485 使用 USART1 始终无法成功

2019-07-21 02:48发布

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




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
18条回答
天涯海QxkJX
1楼-- · 2019-07-21 07:13
初始化:

#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 ");

}


#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 ");

#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 ");
        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;//设置字体为蓝 {MOD}          
        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;
                }                  
               
        }
}

















翼行园子
2楼-- · 2019-07-21 10:33
RX 接 PA9    TX接 PA10 试下
天涯海QxkJX
3楼-- · 2019-07-21 10:36
好巧....我也在调试串口1的485通信
otto1230
4楼-- · 2019-07-21 16:14
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,DISABLE);//停止复位

你把串口时钟关了干嘛?
otto1230
5楼-- · 2019-07-21 17:04
还有中断优先级,主优先级和副优先级是有取值氛围限制的
maven10
6楼-- · 2019-07-21 21:54
otto1230 发表于 2019-4-12 10:21
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口1
    RCC_APB2PeriphResetCmd(RCC ...

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

一周热门 更多>