STM32HAL库学习笔记六——串口通信

HAL库快速部署I2C

本文主要介绍如何使用STM32CubeMX快速部署串口通信,并与定时器结合进行数据收发的实验。



通信的相关基本概念

串行通信:指设备之间使用少量数据线,一位一位地传输数据的通信方式。
并行通信:指设备之间使用多根数据线,同时进行多位数据传输的通信方式。

单工:指数据只能单向发送或者单向接收的通信方式。
半双工:指数据既可以发送也可以接收,但同一时刻只能发送或者接收。
全双工:指数据在同一时刻既可以发送也可以接收。

同步通信:数据传输过程中会依据时钟信号进行同步,在时钟信号的某个电平或者边沿对数据信号进行采样。
异步通信:数据传输过程中不需要时钟信号,通常在数据信号中加入起始位、停止位、校验位等标识位。

比特率:指每秒传输的二进制位数。
波特率:指每秒传输的码元数量,码元个人的理解就是另一种表示信息的形式,我们将固定时间间隔内的二进制信息划分为一个码元,比如00、01、11、10,分别表示1、2、3、4,这样把信号视为用码元表示了。一个码元所含比特数=log2(码元进制数)


串口通信基本知识

串口通信是一种串行通信方式,物理层现在基本由TXD、RXD和GND三条信号线组成,协议层包括起始位、主体数据、校验位以及停止位。
起始位和停止位:数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。
主体数据:通常约定为5、6、7、8位长。
校验位:在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd)、偶校验(even)、0 校验 (space)、1 校验 (mark) 以及无校验 (noparity)。

定时器与串口的综合应用

一、实验目的

实现如下效果:
1.单片机上电后绿灯亮,0.5s后熄灭,标志系统开启;
2.系统向上位机发送“stm32欢迎您!”;
3.系统蓝灯开始以0.5s闪烁,并开始记录时间,时间格式为“XX:XX:XX”;
4.上位机可以通过格式为“0XBF 控制字 0XFB”格式的命令帧控制计时的开启和暂停。控制字为0XA1为暂停,发送“计时暂停”,蓝灯停止闪烁;0XA2为开始,蓝灯再次闪烁,发送“计时恢复”;发送其他控制字,亮红灯,发送“指令错误”。

二、cubemx配置

1.新建工程,常规配置调试模式、时钟树、项目环境;
2.选择PB0、PB1、PB5配置为GPIO_Out,初始为高电平;
3.选择USART1,配置为异步通信,选择好波特率、数据包长度、校验位、停止位、单工还是全双工,需要使用中断时还要在NVIC设置中使能中断。
在这里插入图片描述
4.选择TIM2,配置时钟源、预分频系数、自动重装载计数、使能定时器中断
在这里插入图片描述

5.GENERATE CODE

三、代码编写

1.宏定义和全局变量

(1)封装点灯函数

#define LEDR_ON HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET)
#define LEDG_ON HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET)
#define LEDB_ON HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET)

#define LEDR_OFF HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET)
#define LEDG_OFF HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET)
#define LEDB_OFF HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET)

#define LEDB_TRIGGER HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1)

(2)全局变量

uint8_t welc[] = {"welcome to STM32!\r\n"};  
uint8_t timp[] = {"Time pause\r\n"};
uint8_t timr[] = {"Time restore\r\n"};
uint8_t errs[] = {"wrong command\r\n"};

uint8_t hh = 0;   //小时
uint8_t mm = 0;		//分钟
uint8_t ss = 0;   //秒钟
uint8_t ssh = 0;	//定时0.5秒
uint8_t timbuf[16]; //存放处理过时间的数组

uint8_t revbuf[3];  //指令接收数组

2.程序主体

(1)主函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	LEDG_ON;
	HAL_UART_Transmit(&huart1,welc,sizeof(welc),10000);
	HAL_Delay(500);
	HAL_TIM_Base_Start_IT(&htim2);   //开时钟
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		HAL_UART_Receive_IT(&huart1,revbuf,sizeof(revbuf));
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(2)串口接收回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart1)
	{
		if((revbuf[0] == 0xBF)&&(revbuf[2] == 0xFB))
		{
			if(revbuf[1] == 0xA0)
			{
				HAL_TIM_Base_Stop(&htim2);    //关时钟
				LEDR_OFF;
				LEDB_ON;
				HAL_UART_Transmit(&huart1,timp,sizeof(timp),10000);
				sprintf((char *)timbuf,"%02d:%02d:%02d\n",hh,mm,ss);
				HAL_UART_Transmit(&huart1,timbuf,sizeof(timbuf),10000);
			}
			else if(revbuf[1] == 0xA1)
			{
				HAL_TIM_Base_Start_IT(&htim2);
				HAL_UART_Transmit(&huart1,timr,sizeof(timr),10000);
				sprintf((char *)timbuf,"%02d:%02d:%02d\n",hh,mm,ss);
				HAL_UART_Transmit(&huart1,timbuf,sizeof(timbuf),10000);
			}
			else
			{
				HAL_TIM_Base_Stop(&htim2);
				LEDB_OFF;
				LEDR_ON;
				HAL_UART_Transmit(&huart1,errs,sizeof(errs),10000);
				sprintf((char *)timbuf,"%02d:%02d:%02d\n",hh,mm,ss);
				HAL_UART_Transmit(&huart1,timbuf,sizeof(timbuf),10000);
			}
		}
		else
		{
				HAL_TIM_Base_Stop(&htim2);
				LEDB_OFF;
				LEDR_ON;
				HAL_UART_Transmit(&huart1,errs,sizeof(errs),10000);
				sprintf((char *)timbuf,"%02d:%02d:%02d\n",hh,mm,ss);
				HAL_UART_Transmit(&huart1,timbuf,sizeof(timbuf),10000);
		}
	}	
}

(3)定时器回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim2)
	{
		LEDG_OFF;		
		LEDB_TRIGGER;
		/***时间处理**/
		ssh++;
		if(ssh == 2)
		{
			ss++;
			ssh =0;
		}
		if(ss == 60)
		{
			mm++;
			ss = 0;
		}
		if(mm == 60)
		{
			hh++;
			mm = 0;
		}
	}
}	


版权声明:本文为weixin_44762233原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。