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

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】
(代码仓库地址:https://gitee.com/luobing4365/yie002-explorer
具体参考博客:YIE002开发探索-Gitee代码仓库说明)

在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的接收发送测试了。

158 total views, 1 views today

发表评论

电子邮件地址不会被公开。