赞
踩
给学校团队成员培训的内容
YC YC
根据航模标准,PWM信号线的频率应该是50Hz,对应的每个周期总时长是20ms,输出到舵机的油门线(控制线,也就是细细的,除了红的是接5V电源,黑的GND,另外那个就是数据线)。
这是航模无线遥控模型的一个标准。信号的有效值与1ms~ 2ms的脉宽有关,与脉冲重复率无关。1~ 2ms的方波脉宽渐变过程对应信号的从小到大的渐变。 脉宽的幅度2.5V~ 6V;所以3~5V工作电压的单片机都适用。
这个PWM信号标准不仅对航模舵机适用对航模电调、飞控同样适用。
用定时器2输出PWM信号,其配置如下图
使用串口1作为控制串口,其配置如下图中
在NVIC配置中打开串口1的中断
在usart.h文件适当位置添加下列代码
#include "stdio.h"
#define U1_BUFFER_SIZE 200 //定义最长接收字节
//定义u1_printf功能,兼容我们平时的使用习惯,功能与printf相似
#define u1_printf(...) HAL_UART_Transmit_DMA(&huart1,\
(uint8_t *)u1_printf_buf,\
sprintf((char*)u1_printf_buf,__VA_ARGS__))
extern uint8_t u1_rx_buf[U1_BUFFER_SIZE];//接收缓存
extern volatile uint8_t u1_rx_len;//接收长度
extern volatile uint8_t u1_recv_end_flag;//接收完成标志
extern uint8_t u1_printf_buf[U1_BUFFER_SIZE];//发送缓存
在usart.c文件适当位置添加下列代码
uint8_t u1_rx_buf[U1_BUFFER_SIZE]; volatile uint8_t u1_rx_len=0; volatile uint8_t u1_recv_end_flag=0; uint8_t u1_printf_buf[U1_BUFFER_SIZE]; /* USER CODE BEGIN USART1_Init 2 */ /*STM32的IDLE的中断产生条件: 在串口无数据接收的情况下,不会产生,当清除IDLE标志位后,必须有 接收到第一个数据后,才开始触发,一但接收的数据断流,没有接收到 数据,即产生IDLE中断 */ __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断 HAL_UART_Receive_DMA(&huart1,u1_rx_buf,U1_BUFFER_SIZE);//打开DMA接收,数据存入rx_buffer数组中 /* USER CODE END USART1_Init 2 */
在stm32f1xx_it.c文件中的串口中断函数修改如下
#include "usart.h" /** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ uint32_t tmp_flag = 0; uint32_t temp; tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位 if((tmp_flag != RESET))//idle标志被置位 { __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位 temp = huart1.Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能 temp = huart1.Instance->DR; //读取数据寄存器中的数据 HAL_UART_DMAStop(&huart1); // temp = hdma_usart1_rx.Instance->CNDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面 u1_rx_len = U1_BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数 u1_recv_end_flag = 1; // 接受完成标志位置1 } /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ }
之后便可以在引用了 usart.h 的文件下则可以通过判断u1_recv_end_flag标志位来知道是否完成串口数据接收,并可以调用u1_printf函数通过串口1发送数据。
例子如下
if(u1_recv_end_flag ==1)
{
u1_printf("rx_len=%d\r\n%s\r\n ",u1_rx_len,u1_rx_buf);//打印接收长度与接收数据
for(uint8_t i=0;i<u1_rx_len;i++)
{
u1_rx_buf[i]=0;//清接收缓存
}
u1_rx_len=0;//清除计数
u1_recv_end_flag=0;//清除接收结束标志位
HAL_UART_Receive_DMA(&huart1,u1_rx_buf,U1_BUFFER_SIZE);//重新打开DMA接收
}
HAL_TIM_PWM_Start 使能PWM输出
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
__HAL_TIM_SetCompare 函数修改CCR,修改比较值,修改占空比
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 100); //控制占空比
main函数中while代码
int angle = 0; /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(u1_recv_end_flag ==1) { u1_printf("rx_len=%d\r\n%s\r\n ",u1_rx_len,u1_rx_buf);//打印接收长度与接收数据 sscanf((char *)u1_rx_buf,"%d\r\n",&angle); if(angle>100)angle = 100; else if(angle<0)angle = 0; __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 1000 + angle * 10); //控制占空比 memset(u1_rx_buf,0,200); u1_rx_len=0;//清除计数 u1_recv_end_flag=0;//清除接收结束标志位 HAL_UART_Receive_DMA(&huart1,u1_rx_buf,U1_BUFFER_SIZE);//重新打开DMA接收 } /* USER CODE END WHILE */
向串口发送0-100的数字 串口回复符合预期 通讯成功 注意选择发送新行
将PWM的输出口PA0和GND连接到示波器表笔的两端 上电观察示波器
示波器可以看到PA0脚的对地电压波形为PWM方波,频率为50Hz,高电平持续时间1.5ms
通过串口向单片机发送100,可以看到PWM波形的高电平持续时间变成2ms
同样通过串口向单片机发送100,可以看到PWM波形的高电平持续时间变成1ms
至此PWM输出测试完成
先对舵机进行接线黄色为信号线 红色为5V电源线 棕色为GND
完成接线后对系统进行上电,可以看到舵机旋转动作
通过串口向单片机发送控制指令,舵机也会有相应的运动动作。
实验成功,加油诶!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。