目录
一、CUBEmx配置
1.设置系统时钟,配置SYS,配置时钟树
编辑
2.配置串口USART1
3.配置NVIC,开启串口中断
编辑4.点击GENERATE CODE输出文件即可
二、代码部分
0.串口重定向——printf
1.关于舵机
2.开启串口中断函数
3.编写串口回调函数
4.主函数部分
三、实验现象:
四、总结
刚从标准库转到HAL学习,最近需要做一个机械臂控制,打算用USART1串口中断的方式控制四个舵机运行,现在记录一下过程,主控使用STM32F103ZET6。(本文只讲中断的接收,舵机控制暂时不涉及)
这里我将中断的优先级设置为12(单独学习串口中断并不需要修改优先级配置,按照0级即可)
我使用CLION进行编写,使用keil的方式也是一样的。
在用户自定义区加上如下代码即可使用:
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
舵机使用了两个180°舵机和两个270°舵机,由于uint8_t最大到255,所以打算使用两个八位去存储舵机旋转的角度。
数据包采用如下形式,通过定义一个数组去存放数据包
uint8_t Rx_data[5];//数据包加上包头一共5个byte
uint8_t Rx_flag=0;//设置一个中断完成的标志位
HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);//开启串口接收中断函数
函数的三个参数,第一个指定是USART1的串口中断,第二个参数指定接受数据的位置,第三个指定数据接收的长度,当串口接收到5个字节的数据时,才会触发中断回调函数。
回调函数仅仅负责将接受完成的标志位置1,处理工作再主函数while循环中进行。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)//首先判断是否是USART1触发的中断
{
Rx_flag=1;
}
}
首先判断标志位,即是否接受完5个字节的数据,判断完成后,先将标志位即Rx_flag清零,否则会一直卡在主循环中,接着开启下一次的串口中断。
if(Rx_flag==1)
{
Rx_flag=0;
HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);
}
接着就是对数据包中的数据进行解析了:
1.首先判断包头包尾是否满足协议规范。然后在处理里面的数据:这里我通过switch语句对舵机的ID进行判断:0x01-0x04代表着四个舵机。
2.关于度数的转换:angle=Rx_data[2] * 256 + Rx_data[3],即高位为Rx_data[2] ,低位为Rx_data[3]。
switch (Rx_data[1]) {
case 0x01: {
printf("Servo_1 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x02: {
printf("Servo_2 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x03: {
printf("Servo_3 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x04: {
printf("Servo_4 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
default:
printf("data_error!");
}
3.处理完数据后需要把Rx_data[]中的值全部清零以便下一次的接收:
for (int i = 0; i < 5; ++i) {
Rx_data[i]=0;
}
4.主循环全部函数
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(Rx_flag==1)
{
Rx_flag=0;
HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);
if(Rx_data[0]==0xaa&&Rx_data[4]==0xff) {
switch (Rx_data[1]) {
case 0x01: {
printf("Servo_1 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x02: {
printf("Servo_2 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x03: {
printf("Servo_3 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
case 0x04: {
printf("Servo_4 turn\r\n");
printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
}
break;
default:
printf("data_error!");
}
}
else
{
printf("Data——error!\r\n");
}
for (int i = 0; i < 5; ++i) {
Rx_data[i]=0;
}
}
}
多数厂家的ZET6带有ch340芯片,不需要单独使用usb转串口的工具,直接使用USB连接电脑即可。
这仅仅是串口中断接收的部分,关于舵机控制会在下一篇文章给出,第一次写文章,能力不足,有许多改进的地方,希望大家批评指正!