嵌入式小作业
呼吸灯实验
首先定义延迟函数,自带的HAL_Delay是毫秒级别的,我们需要微秒级别的。
void Delay(int i){
while(--i);
}
然后进行循环:
while(1){
for(int i=0; i<5000; i++){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
Delay(i);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
Delay(5000-i);
}
for(int i=5000; i<0; i--){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
Delay(i);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
Delay(5000-i);
}
}
总结:
- 让它慢慢亮(亮的时间慢慢变长,暗/灭的时间慢慢变短)
- 让它慢慢变暗(暗/灭的时间慢慢变长,亮的时间慢慢变短)
按钮控制灯的亮灭
使用 KEY UP(WKUP)按钮控制灯的亮灭,WK UP 的电路图如下:

我们需要下拉电阻,将 KEY UP 下拉来保证其属于低电平位置,且需要输入CPU,所以选择Input。WK UP 在PA5引脚处。
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5)
函数是将PA5引脚进行反转,从而实现灯的亮灭。
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){
HAL_Delay(20); // 防抖动
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5); // 实现灯的亮/灭转换
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET); // 一直按着直到抬起则结束循环
HAL_Delay(20); // 防抖动
}
}
串口输入控制灯的亮灭
通过使用串口来控制灯的亮灭,在串口调试工具中输入 on
来控制灯亮,输入off
来控制灯灭,使用HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
函数来接收串口中输入的数据,使用 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
来输出串口中输入的数据。
// 定义变量
uint8_t rxbuff[4]; // 存储on/off
uint8_t renum = 0; // 控制串口输入和输出按序执行
if (renum == 0) {
HAL_UART_Receive(&huart1, rxbuff, sizeof(rxbuff), 1000);
renum = 1;
}
if (renum) {
if (strcmp((char *)rxbuff, "on") == 0) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_UART_Transmit(&huart1, (uint8_t *)"LED0 ON", sizeof("LED0 ON"), 100);
memset(rxbuff,0,sizeof(rxbuff)); // 清除rxbuff存储空间中的数据
} else if (strcmp((char *)rxbuff, "off") == 0) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, (uint8_t *)"LED0 OFF", sizeof("LED0 OFF"), 100);
memset(rxbuff,0,sizeof(rxbuff));
}
renum=0;
}
- memset(rxbuff, 0, sizeof(rxbuff)); 指的是清除rxbuff存储空间中的数据
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
- *huart: 指向 UART 外设的句柄,包含 UART 的配置信息(如波特率、数据位、校验位等)
- *pData: 指向接收数据缓冲区的首地址,用于存储接收到的字节数据
- Size: 指定期望接收的字节数。函数会持续尝试接收直至达到该数量或超时
- Timeout: 设置超时时间。若在指定时间内未完成接收,函数返回
HAL_TIMEOUT
- 返回值:
HAL_OK
:成功接收指定数量的数据。HAL_ERROR
:参数错误(如缓冲区未分配或 UART 未初始化)。HAL_BUSY
:UART 正在执行其他操作(如发送数据)。HAL_TIMEOUT
:超时未完成接收
串口控制灯的亮灭-中断控制
// 定义
uint8_t rxbuff[256]={0};
uint8_t datbuff[256]={0};
uint8_t datcount=0;
// 改写 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 判断当前UART句柄是否指向USART1外设的寄存器基地址
{
datbuff[datcount++] = rxbuff[0];
if(datcount >= 255)
{
datcount=0;
}
// HAL_UART_Transmit(&huart1, rxbuff, strlen((char *)rxbuff), 100);
HAL_UART_Receive_IT(&huart1, rxbuff, 1); // 重新初始化代码保持持续监听
}
}
int main(void)
{
HAL_UART_Receive_IT(&huart1, rxbuff, 1); // 以中断的形式,接收定长的数据(1字节)
}
while(1)
{
if(strcmp((char *)datbuff, "ON")==0)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_UART_Transmit(&huart1, (uint8_t *)"ON", sizeof("ON"), 100);
memset(datbuff, 0, sizeof(datbuff));
datcount=0;
}
else if (strcmp((char *)datbuff, "OFF")==0)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, (uint8_t *)"OFF", sizeof("OFF"), 100);
memset(datbuff, 0, sizeof(datbuff));
datcount=0;
}
}
分析:
中断接收机制
通过
HAL_UART_Receive_IT()
(UART1)启动单字节中断接收,每次接收到数据后触发HAL_UART_RxCpltCallback
回调函数,将数据存入datbuff
缓冲区,并重新使能接收中断。指令解析逻辑
主循环中通过
strcmp
比对datbuff
内容,若匹配”ON”/“OFF”,则控制GPIO引脚电平并通过串口返回响应,最后清空缓冲区和计数清零。if(huart->Instance == USART1)
在 STM32 中,可能存在多个 UART/USART 外设(如 USART1、USART2、USART3)。通过
huart->Instance == USART1
可以明确当前代码操作的是哪个外设实例,避免混淆。HAL_UART_Receive_IT(&huart1, rxbuff, 1);
- 将接收缓冲区的起始地址和长度写入串口句柄(
huart1
)中; - 使能串口接收中断(RXNEIE),允许硬件在接收到数据时触发中断;
- 单次接收特性:此函数仅触发一次接收中断,完成1字节接收后会自动关闭中断。若需持续接收,必须在回调函数中**重新调用
HAL_UART_Receive_IT()
**以重新使能中断; - 这段代码通过中断机制实现了非阻塞式单字节接收,适用于需要实时响应但数据量较小的场景。使用时需注意在回调函数中重新初始化接收,以保持持续监听
- 将接收缓冲区的起始地址和长度写入串口句柄(
扩展:printf
printf 将数据输出到 stdout 文件
单片机没有文件系统,需要改变 printf 的输出方向,往串口输出可以重定义
fputc
函数,改变输出方向int fputc(int c, FILE * stream) { HAL_UART_Transmit(&huart1, (uint8_t *)&c, 1, 1000); return c; }