0

YIE002开发探索08-串口(485)

 2 years ago
source link: http://yiiyee.cn/blog/2021/08/11/yie002%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a208-%e4%b8%b2%e5%8f%a3485/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

在YIE002开发探索05中,我们介绍过RS485一些基本参数。RS485通信协议由RS232协议改进而来,将物理层改为了差分信号进行传输,因此其抗干扰性强、传输距离远,比较广泛地应用于噪声干扰比较大的工业控制环境中。

1 YIE002上的RS485

RS485的电气特性与RS-232不大一样,采用两线的时候为半双工。其基本的特点包括:

1) 接口电平低,不易损坏芯片。RS485 的电气特性:逻辑“1”以两线间的电压差为+(2~6)V 表示;逻辑“0”以两线间的电压差为-(2~6)V 表示。接口信号电平比 RS232 降低了,不易损坏接口电路的芯片,且该电平与 TTL 电平兼容,可方便与 TTL 电路连接;
2) 传输速率高。 10 米时, RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输速度可达 100Kbps;
3) 抗干扰能力强。 RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好;
4) 传输距离远, 支持节点多。 RS485 总线最长可以传输 1200m 以上(速率≤100Kbps)一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点,最大的可以支持到 400 个节点。

从软件工程师的角度来看,RS485与RS232的编程几乎一样,需要关注的是其半双工的特性(因为开发板上使用的是两线),必须通过使能脚配置其为发送状态或接收状态。

如图1所示,给出了YIE002的RS485部分的线路图。

图1 YIE002的RS485

开发板YIE002采用SP3485作为收发器,其A、B总线接口,用于连接485总线。从图中可以看出,485_TR与STM32F103C8T6的PB0连接,当其电平为低时,RS485接收数据;电平为高时,RS485发送数据。

开发板上使用了串口3实现485,下面将在YIE002开发探索06的基础上,实现RS485的数据收发。

2 YIE002-STM32的串口编程(485)

从软件角度,RS485和RS232的代码是一样的,所要注意的是对RS485接收或发送的使能。因此,本篇的代码编写比较简单,具体步骤如下。

2.1 串口(485)的Cube MX图形配置

如图2所示,在Pinout & Configuration栏的Connectivity中,将USART3的模式设置为异步通信。

图2 设置串口3

在设置中可以看到,USART3旁边有黄色感叹号出现。这是因为用来控制LED灯的PB12、PB13和PB14,分别用于USART3_CK、USART3_CTS和USART3_RTS,导致Cube MX出现了警告提示。在实际应用中,我们并没有用到这些功能,维持原来的引脚配置就可以了。

然后在NVIC的配置界面中,设置串口3的中断优先级,如图3所示。

图3 设置串口3的中断优先级

完成上述配置后,选择GENERATE CODE按钮,生成代码。

2.2 添加应用代码

编写USART3的接收和发送代码,与之前编写USART1的步骤类似。具体如下:

1) 设置USART3的IDLE中断

在main.h中,添加USART3的IDLE中断处理函数的声明。

/* USER CODE BEGIN Includes */
void MyUser_UART1_IDLE_IRQHandler(UART_HandleTypeDef *huart);
void MyUser_UART3_IDLE_IRQHandler(UART_HandleTypeDef *huart);

在stm32f1xx_it.c中,增加对USART3的IDLE中断的调用。
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */

  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */
	if(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart3);
		MyUser_UART3_IDLE_IRQHandler(&huart3);
	}
  /* USER CODE END USART3_IRQn 1 */
}

在main.c的USART3初始化函数MX_USART3_UART_Init()中,添加对IDLE中断的使能语句。

/* USER CODE BEGIN USART3_Init 2 */
		//此处使能IDLE中断
	__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);    //使能IDLE中断
	__HAL_UART_CLEAR_IDLEFLAG(&huart3);             //清除IDLE挂起标志位 
  /* USER CODE END USART3_Init 2 */

2) 添加USART3相关的全局变量

#define USART3_REC_LEN 200    //接收的最大字符串长度
uint8_t Usart3PackageFlag;		//接收到完整的包的标志,即一串数据接收完毕;
uint8_t bUsart3RxBuff[USART3_REC_LEN]; //接收缓冲,最大USART1_REC_LEN个字节
uint16_t	wUsart3RxNumber=0;		//接收到的数据字节数
uint8_t bUsart3Buffer[1]; //接收用的暂存缓冲区
//IDLE防抖使用的标志:只有接收到数据后,IDLE才有效,防止抖动
//1:数据接收到了;
uint8_t Usart3DataFlag;

3) 编写USART3的IDLE中断处理函数

在main.c的USER CODE BEGIN 4处,添加函数的实现。

//USART3 IDLE中断
void MyUser_UART3_IDLE_IRQHandler(UART_HandleTypeDef *huart)
{
	if(Usart3DataFlag==1)		//只有之前接收到数据了,才证明数据包传送完成,主要用来去除空闲中断的抖动
    {
			Usart3PackageFlag=1;
			Usart3DataFlag=0;
    }
}

4) 添加USART3的接收中断处理

在main.c的接收中断处理函数HAL_UART_RxCpltCallback()中,添加对USART3数据接收的处理。

if(huart ==&huart3)  //串口3-485
	{
		if(Usart3PackageFlag==0)		//上一个包处理完了或初次处理
		{
			bUsart3RxBuff[wUsart3RxNumber++]=bUsart3Buffer[0];
			Usart3DataFlag=1;
			if(wUsart3RxNumber>=USART3_REC_LEN)//超过此数目,则认为包已经接收完了
			{
				Usart3DataFlag=0;
				Usart3PackageFlag=1;		
			}
		}
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);  //设置485为接收模式
		if(HAL_UART_Receive_IT(&huart3, bUsart3Buffer, 1) != HAL_OK) //  receive 1 byte data, and put data
		{
			Error_Handler();
		}
	}

5) 添加应用处理代码

在主程序main()中,添加应用所需的代码。

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);  //设置485为接收模式
    HAL_UART_Receive_IT(&huart3, bUsart3Buffer, 1); 		//使能接收中断
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		//robin 20210810
		if(Usart3PackageFlag==1)	//接收到数据包 串口3处理
		{
			Usart3PackageFlag=0;
			rUsart_len=wUsart3RxNumber;
			wUsart3RxNumber=0;
			for(i=0; i<rUsart_len; i++)
				rUsartData[i]=bUsart3RxBuff[i];
			
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);  //设置485为发送模式
            if(HAL_UART_Transmit(&huart3,rUsartData,rUsart_len,5000)!=HAL_OK)
			{
				Error_Handler();
			}
			HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);  //设置485为接收模式	
		}
  }
  /* USER CODE END 3 */

需要注意的是,发送数据的时候采用了阻塞模式的发送函数。主要是因为485有接收和发送模式的使能动作,如果不是发完数据返回,马上就会进入接收模式,导致发送数据失败。

当然,也可以使用非阻塞式的发送模式,那么设置485位接收模式的代码,就不能在此处添加了。应该在发送完成后触发的中断处理函数中,将485设置为接收模式。

2.3 测试

编写完成后,将代码下载至YIE002开发板,就可以进行测试了。

测试的时候,可以使用两个开发板对接,修改应用代码,进行测试。我使用了一个专用的485转USB的工具,直接与PC机进行收发测试。

连接图如图4所示。

图4 YIE002的485测试连接图

将YIE002开发板上的485-A与485转USB工具的A相连,开发板的485-B与485转USB工具的B相连,就完成了硬件连接了。

485转USB工具连接到PC机上,在PC机上运行串口调试助手,就可以进行485的接收发送测试了。

43 total views, 1 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK