1.CubeMX配置
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE * f)
{
uint8_t ch = 0;
while(HAL_UART_Receive(&huart3,&ch, 1, 0xffff)!=HAL_OK);
return ch;
}
串口配置
其它时钟和以前一样,配置为72MHZ即可
串口的基本信息查看
11.串口通信及DS18B20使用
2.串口操作
21.串口发送
(1)阻塞模式串口发送
MCU的CPU一个字节一个字节的发送丢给串口模块,然后看着串口模块将这个字节发送出去,然后CPU去拿下一个字节丢给串口模块。直到本次发送的所有自己全部发送完,然后才去做其他事情。
(2)中断模式串口发送
MCU的CPU向串口模块丢一个字节,然后串口模块慢慢发,CPU丢完这个字节后跳出去做其他事情,等串口模块发完这个字节后产生一个中断,中断会通知CPU过来继续丢下一个字节。
阻塞式发送:HAL_UART_Transmit
阻塞式接收:HAL_UART_Receive
总结:阻塞式发送实际用的很多,因为编程简单。缺陷就是浪费了高速CPU的部分性能,没有追求到串口发送和整个系统性能的最高。
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
2.2串口接收
阻塞式串口接收
中断式串口接收
一般使用中断串口接收
注意在Cube中打开中断
如下是中断处理程序
注意要开启中断
HAL_UART_Receive_IT(&huart1, &receive_char, 1);
//开启中断
uint8_t receive_char;
//这个就是HAL库对接的中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
//这里就是真正的中断处理代码
//receive_char 是全局变量 接收
//这里的处理就是接收到一个字节,原封不动的发出去
HAL_UART_Transmit(&huart1, &receive_char, 1,0xFF);
//确定本次接收完毕,同时开启下一次接收
while(HAL_UART_Receive_IT(&huart1, &receive_char, 1) != HAL_OK);
}
}
HAL_UART_Receive_IT(&huart1, &receive_char, 1);
2.3串口接收和处理
指令:
add
sub
指令结束符:
‘;’
指令中遇到回车和空格、Tab怎么办? 不进行处理
实现思路分析:
//这个就是HAL库对接的中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
rev_buf[ind++] = receive_char;
//这里就是真正的中断处理代码
//receive_char 是全局变量 接收
//这里的处理就是接收到一个字节,原封不动的发出去
//HAL_UART_Transmit(&huart1, &receive_char, 1,0xFF);
//确定本次接收完毕,同时开启下一次接收
while(HAL_UART_Receive_IT(&huart1, &receive_char, 1) != HAL_OK);
}
}
uint8_t receive_char;
uint8_t rev_buf[20]; //串口接收到字符串暂存到rev_buf
uint8_t ind = 0; //ind 为buf的索引
uint8_t i = 0;
//开启中断
HAL_UART_Receive_IT(&huart1, &receive_char, 1);
//循环
while (1)
{
//在主循环中处理接收到的buf指令
//第一步,先遍历整个buf,找到是否有分号
for (i = 0; i < ind; i++)
{
if (rev_buf[i] == ';')
{
//找到了,说明已经接收完一个命令了,可以进行处理了
if ((strncmp((char*)rev_buf, "add;", 4)) == 0)
{
//执行add指令即可
printf("增加");
}
else if ((strncmp((char*)rev_buf, "sub;", 4)) == 0)
{
//执行add指令即可
printf("减少");
}
else
{
printf("unknown");
}
//指令识别执行完成,要把buf和index清空
memset(rev_buf, 0, 20);
ind = 0;
}
}
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
2.4串口总结
(1)基于HAL库和CubeMX工具的开发,用起来很简单
(2)遇到问题大部分是因为不熟悉这一套,是最耗时间的
(3)解决问题靠调试能力功底、经验等,是核心竞争力
(4)后续发展:字符串处理拓展
(5)未尽事宜:串口的DMA发送和接收
3.按键中断
PA0为中断按键
PG6为LED
3.1 配置
时钟配置就不说了
将A0设置为外部中断
引脚配置为下降沿触发
NVIC使能
如需要配置优先级 可以在NVIC中进行配置
重写中断程序即可
翻转LED
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == Key_Pin)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
3.2 总结
(1)用Cube生成中断很方便
(2)很多细节都进行了隐藏,还是比较难找的