1.cubemx设置
参考文章
时钟设置
高速时钟配置
将HCLK设置为最大频率72MHz
串口设置
参数设置
USAT4
串口4
Baud Rate(波特率)
9600Bits/s
Work Length(传输数据长度)
8 Bit
Parity(奇偶校验位)
无
STOP Bits(停止位)
1
Data Direction(数据方向)
发送和接收都使能
打开中断
2. 串口基础知识
USART(Universal Synchronous/Asynchronous Receiver/Transmitter,通用同步/异步接收器/发送器)是用于串行通信的一个硬件模块,支持全双工通信,即可以同时进行数据的接收和发送。
工作模式
-
异步模式:
- 数据在没有同步时钟信号的情况下传输。
- 使用起始位、数据位、奇偶校验位和停止位来同步和校验数据。
- 常用于标准串口通信,如 RS-232。
-
同步模式:
- 数据和时钟信号一起传输,接收端使用同步时钟信号来接收数据。
- 常用于 SPI、I2C 等高速通信。
波特率
波特率(Baud Rate)是指数据传输的速率,表示每秒钟传输的比特数。常见的波特率有 9600、115200 等。波特率越高,数据传输速度越快,但对信号的质量要求也越高。
数据帧格式
在异步模式下,数据帧格式通常如下:
- 起始位(Start Bit):1 个比特,用于标识帧的开始。
- 数据位(Data Bits):通常是 8 个比特,可以是 5 到 9 个比特不等。
- 奇偶校验位(Parity Bit):用于错误检测,可以设置为无校验、奇校验或偶校验。
- 停止位(Stop Bit):1 或 2 个比特,用于标识帧的结束。
接口通过三个引脚与其他设备连接在一起(见图248)。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
3.使用函数
串口中断模式接收
HAL_UART_Receive_IT();
中断回调函数
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
4.代码
记得在主函数里面开启中断
HAL_UART_Receive_IT(&huart4, (uint8_t *)&aRxBuffer, 1);
main(while循环中)
HAL_ADC_Start(&hadc1); //启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待转换完成,时间为50ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取AD值
printf("ADC1: %d \r\n",ADC_Value);
printf("PA5 voltage: %.4f \r\n",ADC_Value*3.3f/4096);
}
HAL_Delay(500);
HAL_UART_Transmit(&huart4, (uint8_t *)"Hello", 5,0xFFFF);
串口中断函数(包头0x2C 0x12 包尾0x5B)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
if(RxState==0)
{
RxBuffer[Uart2_Rx_Cnt++] = aRxBuffer;
if((RxBuffer[Uart2_Rx_Cnt-1] == 0x12)&&
(RxBuffer[Uart2_Rx_Cnt-2] == 0x2C)) //head
{
RxState=1;
Uart2_Rx_Cnt=0;
}
}
else if(RxState==1)
{
RxBuffer[Uart2_Rx_Cnt++] = aRxBuffer;
if(Uart2_Rx_Cnt >= 255)
{
Uart2_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer));
RxState = 0;
return;
}
else if( RxBuffer[Uart2_Rx_Cnt-1] == 0x5B )
{
RxBuffer[Uart2_Rx_Cnt-1] =0x00;
Uart2_Rx_Cnt = 0;
RxState = 0;
if(strcmp(RxBuffer,"Hello")==0)
{
printf("Hello\n");
}
memset(RxBuffer,0x00,sizeof(RxBuffer));
}
}
HAL_UART_Receive_IT(&huart4, (uint8_t *)&aRxBuffer, 1);
}
重定义Printf函数(可以在自己的c里面)
#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart4; //声明串口
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart4, &ch, 1, 0xffff);
return ch;
}
5.实验现象
加上上次的ADC实验结果
6. 附
重定义Printf函数代码解释
函数:fputc
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
重定向标准库函数 printf
的输出到指定的串口(在这里是 huart4
)。
-
参数:
int ch
:要输出的字符。FILE *f
:这是一个文件指针,在调用printf
等标准库函数时传递,但在重定向中并不使用它。
-
实现过程:
HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
- 将字符
ch
发送到串口huart4
。 (uint8_t *)&ch
:要发送的数据,ch
被强制转换为指向uint8_t
类型的指针。1
:发送的数据长度为 1 字节。0xffff
:发送超时时间。
- 将字符
return ch;
- 返回传入的字符。
函数:fgetc
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart4, &ch, 1, 0xffff);
return ch;
}
重定向标准库函数 getchar
和 scanf
的输入从指定的串口(在这里是 huart4
)读取数据。
参数:
-
FILE *f
:这是一个文件指针,通常在调用getchar
、scanf
等标准库函数时传递,但在重定向中并不使用它。 -
实现过程:
uint8_t ch = 0;
- 用于存储接收到的数据。
HAL_UART_Receive(&huart4, &ch, 1, 0xffff);
- 从串口
huart4
接收一个字节的数据并存储到ch
中。 &ch
:ch
被传递给接收函数。1
:接收的数据长度为 1 字节。0xffff
:超时时间。
- 从串口
return ch;
- 返回接收到的字符。