STM32L4 HAL库通过串口通信改变PWM占空比

STM32 L4 通过串口通信改变PWM占空比 HAL库

使用串行通信的目的是为了让上位机能控制STM32来改变PWM的输出

目录

  • STM32 L4 通过串口通信改变PWM占空比 HAL库
    • 一、PWM初始化
    • 二、串口UART初始化
    • 三、赋值
    • 四、最后附上效果图

一、PWM初始化

#include "pwm.h"TIM_HandleTypeDef TIM4_Handler;         //定时器4PWM句柄
TIM_OC_InitTypeDef TIM4_CHnHandler;	    //定时器4句柄void TIM4_PWM_Init(u16 arr, u16 psc)
{TIM4_Handler.Instance = TIM4;          				//定时器4TIM4_Handler.Init.Prescaler = psc;     				//定时器分频TIM4_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式TIM4_Handler.Init.Period = arr;        				//自动重装载值TIM4_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;HAL_TIM_PWM_Init(&TIM4_Handler);       				//初始化PWMTIM4_CHnHandler.OCMode = TIM_OCMODE_PWM1; 			//模式选择PWM1TIM4_CHnHandler.Pulse = arr / 2;       				//设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%TIM4_CHnHandler.OCPolarity = TIM_OCPOLARITY_HIGH; 	//输出比较极性为低HAL_TIM_PWM_ConfigChannel(&TIM4_Handler, &TIM4_CHnHandler, TIM_CHANNEL_3); //配置TIM4通道3HAL_TIM_PWM_Start(&TIM4_Handler, TIM_CHANNEL_3); 	//开启PWM通道3}void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_TIM4_CLK_ENABLE();				//使能定时器4__HAL_RCC_GPIOB_CLK_ENABLE();				//开启GPIOB时钟GPIO_Initure.Pin = GPIO_PIN_8; //PB8GPIO_Initure.Mode = GPIO_MODE_AF_PP;  		//复用推挽输出GPIO_Initure.Pull = GPIO_PULLUP;        	//上拉GPIO_Initure.Speed = GPIO_SPEED_HIGH;   	//高速GPIO_Initure.Alternate = GPIO_AF2_TIM4;		//PB8复用为TIM2_CH1.CH2HAL_GPIO_Init(GPIOB, &GPIO_Initure);
}void TIM_SetTIM4Compare3(u32 compare)
{TIM4->CCR3 = compare;
}

这里用的是定时器TIM4的3通道,当然也可以改为其他的定时器,具体请参考手册

在这里插入图片描述

二、串口UART初始化

偷下懒,直接拿正点原子的例子程序修改了一下。
示例用的是UART1
引脚是PA9(TX),PA10(RX)

#include "usart.h"
#include "delay.h"
#include  
#include extern int mypwm;
extern u16 pwmval;
extern u8 chun[10];
extern int len;#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{int handle;
};FILE __stdout;
/*** @brief	定义_sys_exit()以避免使用半主机模式** @param	void** @return  void*/
void _sys_exit(int x)
{x = x;
}
/*** @brief	重定义fputc函数** @param	ch		输出字符量* @param	f		文件指针** @return  void*/
int fputc(int ch, FILE *f)
{while((USART1->ISR & 0X40) == 0); //循环发送,直到发送完毕USART1->TDR = (u8) ch;return ch;
}
#endif#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA = 0;     //接收状态标记UART_HandleTypeDef UART1_Handler; //UART句柄/*** @brief	初始化串口1函数** @param	bound	串口波特率** @return  void*/
void uart_init(u32 bound)
{//UART 初始化设置UART1_Handler.Instance = USART1;					  //USART1UART1_Handler.Init.BaudRate = bound;				  //波特率UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式UART1_Handler.Init.StopBits = UART_STOPBITS_1;	  //一个停止位UART1_Handler.Init.Parity = UART_PARITY_NONE;		  //无奇偶校验位UART1_Handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控UART1_Handler.Init.Mode = UART_MODE_TX_RX;		  //收发模式HAL_UART_Init(&UART1_Handler);					    //HAL_UART_Init()会使能UART1__HAL_UART_ENABLE_IT(&UART1_Handler, UART_IT_RXNE); //开启接收中断HAL_NVIC_EnableIRQ(USART1_IRQn);					//使能USART1中断通道HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);				//抢占优先级3,子优先级3printf("\r\n串口已准备--\r\n");
}/*** @brief	HAL库串口底层初始化,时钟使能,引脚配置,中断配置** @param	huart	串口句柄** @return  void*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{//GPIO端口设置GPIO_InitTypeDef GPIO_Initure;if(huart->Instance == USART1) //如果是串口1,进行串口1 MSP初始化{__HAL_RCC_GPIOA_CLK_ENABLE();				//使能GPIOA时钟__HAL_RCC_USART1_CLK_ENABLE();				//使能USART1时钟GPIO_Initure.Pin = GPIO_PIN_9;				//PA9GPIO_Initure.Mode = GPIO_MODE_AF_PP;		//复用推挽输出GPIO_Initure.Pull = GPIO_PULLUP;			//上拉GPIO_Initure.Speed = GPIO_SPEED_FAST;		//高速GPIO_Initure.Alternate = GPIO_AF7_USART1;	//复用为USART1HAL_GPIO_Init(GPIOA, &GPIO_Initure);	   	//初始化PA9GPIO_Initure.Pin = GPIO_PIN_10;				//PA10HAL_GPIO_Init(GPIOA, &GPIO_Initure);	   	//初始化PA10}}/*** @brief	串口1中断服务程序** @remark	下面代码我们直接把中断控制逻辑写在中断服务函数内部* 			说明:采用HAL库处理逻辑,效率不高。** @param   void** @return  void*/
void USART1_IRQHandler(void)
{u8 Res;int i;if((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_RXNE) != RESET)) //接收中断(接收到的数据必须是0x0d 0x0a结尾){HAL_UART_Receive(&UART1_Handler, &Res, 1, 1000);if((USART_RX_STA & 0x8000) == 0) //接收未完成{if(USART_RX_STA & 0x4000) //接收到了0x0d{if(Res != 0x0a)USART_RX_STA = 0; //接收错误,重新开始else USART_RX_STA |= 0x8000;	//接收完成了}else //还没收到0X0D{if(Res == 0x0d)USART_RX_STA |= 0x4000;else{USART_RX_BUF[USART_RX_STA] = Res;USART_RX_STA++;if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0; //接收数据错误,重新开始接收}}}}HAL_UART_Transmit(&UART1_Handler, &Res, 1, 1000);//发送数据函数,通过USART1通道发送res数据出去if(USART_RX_STA&0x8000)                    {					   len=USART_RX_STA&0x3fff;//计算出接受数据的总长度for(i=0;i<len;i++){chun[i] = (USART_RX_BUF[i]-0x30);	USART_RX_BUF[i]=0;	//HAL_UART_Transmit(&UART1_Handler, &chun[i], 1, 1000);//发送数据函数,通过USART1通道发送res数据出去}USART_RX_STA = 0; }HAL_UART_IRQHandler(&UART1_Handler);
}#endif

主要修改的地方在接收数据的部分,我用len=USART_RX_STA&0x3fff
计算出串口接收到数据的长度,然后把接收缓存USART_RX_BUF中的每一位逐个放到chun[ ]数组中。
由于pc端每次发送的是字符类型的数据,例如‘1’对应的ASCII码是0x31,0对应的是0x30。那么对于输入的数字每个都要减去0x30就会得到 01,02,03.。。。
在这里插入图片描述

三、赋值

初始化都处理完了之后就准备在主函数进行赋值了

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "pwm.h"#define ARR1 1000
#define PSC1 80int mypwm=0;
u16 pwmval = 0;			
u8 chun[10];
int len=0;int main(void)
{HAL_Init();SystemClock_Config();		//初始化系统时钟为80Mdelay_init(80); 			//初始化延时函数    80M系统时钟uart_init(115200);			//初始化串口,波特率为115200TIM4_PWM_Init(ARR1 - 1, PSC1 - 1);//TIM2时钟频率 80M/80=1M   计数频率1M/1000=1KHZ     默认占空比为50%pwmval=0;while(1){if(len==2){mypwm =((int)chun[0]*10 + (int)chun[1]);}else if(len==3){mypwm =((int)chun[0]*10*10 + (int)chun[1]*10 + (int)chun[2]);if(mypwm>100){printf("\r\n占空比不能超过100%\r\n");mypwm = 0;len=0;}}else if(len==1){mypwm =((int)chun[0]);}else if(len>3){printf("\r\n请输入长度 < 3的字符\r\n");printf("\r\n占空比最大为100,不用输入百分号\r\n");len=0;}			pwmval = ARR1*(mypwm*1.0/100);//计算占空比并赋值if(pwmval>ARR1)pwmval=ARR1;//限幅TIM_SetTIM4Compare3(pwmval);//输出PWM}
}

四、最后附上效果图

占空比为30%在这里插入图片描述
在这里插入图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部