6. STM32-NVIC USART

USART介绍

USART全名为通用同步/非同步收发传输器(universal synchronous asynchronous receiver transmitter),可以透过串列通讯的方式进行传输。
STM32具有全双工的USART,同时支援同步/非同步与半双工/全双工等等模式,STM32已将预设的USART2连接到烧录器同时连结到电脑上,可以直接使用。
https://ithelp.ithome.com.tw/upload/images/20220312/20146325GeoVTAW3HH.png

半双工 / 全双工区别

  • 半双工 : 允许两台设备之间双向资料传输,但无法同时进行。也就是说同一时间内只能允许一个设备传送资料,另一个设备要重送资料只能等待。
  • 全双工 : 同时允许两台设备进行双向的资料传输(传送与接收)

同步/非同步

  • 同步 : 需额外提供SCLK,让两设备可以同步收发资料。不需要Start/stop bit,一次可以传比较多的资料。
  • 非同步: 传送资料的时候透过起始位与结束位来确定资料的收发状态
    https://ithelp.ithome.com.tw/upload/images/20220312/201463255Sa11y3Szj.png
    USART每一次传输资料时,会以上图一个讯框作(frame)为一个单元,其中包含开头与结尾的起始/结束位元与中间的8 bit/9bit资料。图中可以看到在TX发送资料於起始位时处於低电位,结束则处於高电位。
    其中有分为8bit资料与9bit资料两种讯框,可以透过IDE当中.ioc去做详细的设置。
    https://ithelp.ithome.com.tw/upload/images/20220312/201463251ex6KzvuzQ.png
    https://ithelp.ithome.com.tw/upload/images/20220312/20146325yX0p0x37RV.png
    详细暂存器与特性可以参考STM32中文参考手册

函数介绍-发送

1.HAL_UART_Transmit :轮询方式,阻塞式发送函数(必须等资料传送完成後MCU才去做其他事情)

//*huart : 看选择哪个USART填入对应编号
//*pData : 要传送的资料Buf指针
//Size : 资料长度
//Timeout : 逾时时间
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

2.HAL_UART_Transmit_IT : 中断方式,非阻塞发送函数

//*huart : 看选择哪个USART填入对应编号
//*pData : 要传送的资料Buf指针
//Size : 资料长度
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
  1. HAL_UART_TxCpltCallback :串列埠发送中断回调函数
void HAL_UART_TxCpltCallback(UART_HandleTypeDef  *huart);
  1. HAL_UART_TxHalfCpltCallback : 串列埠发送一半中断回调函数
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef  *huart)

应用方式

//使用中断方式
//将buf当中的前10笔数据发送到usart2,接着等发送完成後进到回调函数
HAL_UART_Transmit_IT(&huart2,buf,10);

void HAL_UART_TxCpltCallback(UART_HandleTypeDef  *huart) 
{         
    if(huart->Instance == USART2);         
    {             
        HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); 
    }
}

//使用轮询方式
HAL_UART_Transmit(&huart2,buf, 10, 100);
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); 

函数介绍-接收

  1. HAL_UART_Receive : 轮询方式,阻塞式接收函数(必须等资料传送完成後MCU才去做其他事情)
//*huart : 看选择哪个USART填入对应编号
//*pData : 要接收的资料Buf指针
//Size : 等待接收的资料长度
//Timeout : 逾时时间
HAL_StatusTypeDef  HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData,  uint16_t Size, uint32_t Timeout);
  1. HAL_UART_Receive_IT : 中断方式,非阻塞发送函数
//*huart : 看选择哪个USART填入对应编号
//*pData : 要接收的资料Buf指针
//Size : 等待接收的资料长度
HAL_StatusTypeDef  HAL_UART_Receive_IT(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size);
  1. HAL_UART_RxCpltCallback :串列埠接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);
  1. HAL_UART_TxHalfCpltCallback : 串列埠接收一半中断回调函数
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef  *huart);

应用方式

//使用中断,非阻塞方式
//接收USART2的一个byte,假设是0xFF将板载LED灯反转
HAL_UART_Receive_IT(&huart2,  &buf, 1);
  
void HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)  
{        
    if(huart->Instance == USART2)    
    {       
        if(buf == 0xFF)      
         HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    }
}

//使用轮询方式
HAL_UART_Receive(&huart2,buf, 1, 100);

函数介绍-查询

  1. HAL_UART_GetState : 查询发送是否正处於忙碌状态或是接收是否结束了
HAL_UART_GetState();
//EX
while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX)   //查询UART是否发送结束

范例-透过轮询方式传送与接收

  1. 先在最上方宣告buf
char buf[] = "USART2 初始化中.....\r\n";
char buf1[] = "初始化完成\r\n";
char Receivebuf[7];
  1. 在mian当中写进传送与接收函数
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_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
	if(HAL_OK == HAL_UART_Transmit(&huart2, (uint8_t*)buf, sizeof(buf), 1000)) //显示初始化是否成功
	{
		HAL_Delay(1000);
		HAL_UART_Transmit(&huart2, (uint8_t*)buf1, sizeof(buf1), 1000); //显示初始化成功字串
	}
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		if (HAL_OK == HAL_UART_Receive(&huart2, (uint8_t*)Receivebuf, 7, 10000)) //如果成功接收到了资料,则将资料传送出去
		{
			HAL_UART_Transmit(&huart2, (uint8_t*)Receivebuf, 7, 10000);
	  }
		HAL_Delay(500);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

这边介绍一下我觉得挺好用的调适工具-串口调适助手,可以到Microsoft Store当中去下载~
https://ithelp.ithome.com.tw/upload/images/20220312/20146325KOXuCfcJww.png


范例-透过中断方式传送与接收

  1. 同样先宣告buf
char Txbuf[] = {"USART 中断测试\r\n"};
char AckBuf[] = {"收到讯息\r\n"};
char Rxbuf[7];
  1. 到.ioc当中将USART中断开启
    https://ithelp.ithome.com.tw/upload/images/20220312/201463255FVr0BdXJ6.png

  2. 先在main当中写上Receive_IT与Transmit_IT函数,会先传送上方Txbuf当中的字串做测试,接着要先启用Receive_IT否则不会进入接收中断。

/* USER CODE BEGIN 2 */
  HAL_UART_Transmit_IT(&huart2, (uint8_t*)&Txbuf, sizeof(Txbuf));
  HAL_UART_Receive_IT(&huart2, (uint8_t*)&Rxbuf, 7);
  /* USER CODE END 2 */
  1. 编写接收中断回调函数(如果传送中断要连续使用的话,要记得先检查是否已传送完成)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == huart2.Instance)
	{
        //这边也可以将AckBuf改为Rxbuf,就可以看到接收到的讯息~
		HAL_UART_Transmit_IT(huart, (uint8_t*)&AckBuf, sizeof(AckBuf));
		HAL_UART_Receive_IT(huart, (uint8_t*)&Rxbuf, 7);
	}
}

https://ithelp.ithome.com.tw/upload/images/20220312/20146325ABPTZyMXGU.png
以上内容如果有误的话,麻烦各位通知我。感谢~


<<:  Python & Celery 学习笔记_基本操作

>>:  .NET Framework4.7.2 制作 Web API 图片上传接收功能

用React刻自己的投资Dashboard Day15 - 投资Dashboard 2.0版 Wireframe

有了总体经济的图表之後,接下来就要来制作各国股市的资讯站,笔者最常看的就是台股的资讯,其次则是美股、...

浮点数的二进位表达方法

浮点数的二进位表达方法 浮点运算知识点 小数二进制表达 与整数的二进制表达相同我们可以假设任意小数的...

Day 26: Behavioral patterns - Strategy

目的 如果物件本身有负责计算的方法,且该方法依照给予的参数,会有不同的计算结果,那可以将计算的部分封...

把 HackMD 当成网站後台

把 HackMD 当成网站後台 前面已经分享了如何完全透过网页的操作,就可以把 VuePress 网...

Day06 UIKit 05 - 纯代码编写 Code

在开发前我们需要知道,在 iOS 中,我们可以采取 Storyboard、XIBs 或是纯 Code...