【STM32嵌入式系统设计与开发】——14PWM(pwm脉宽输入应用)

这里写目录标题


STM32资料包:

百度网盘下载链接:链接:https://pan.baidu.com/s/1mWx9Asaipk-2z9HY17wYXQ?pwd=8888

提取码:8888


一、任务描述

二、任务实施

观察电路图:

TXD(底板) ------------------------> PA10

RXD(底板) ------------------------> PA9

D1 (底板) ------------------------> PA1

使用USB-AB型数据线,连接15核心板USB口,串口发送接收到的数据。

1、WWDG工程文件夹创建

步骤1:复制工程模板"1_Template"重命名为"10_PWM"。

步骤2:修改项目工程名,先删除projects文件夹内除了Template.uvprojx文件外的所有内容并修改为"WWDG.uvprojx"。并删除output/obj和output/lst中的所有文件。

步骤3:运行"PWM.uvprojx"打开目标选项"Options for Target"中的"Output"输出文件,并修改可执行文件名称为"PWM"点击"OK"保存设置。最后点击"Rebuild"编译该工程生成Usart文件。

步骤4:复制"2_SingleKey"中的"1_LED"和"SingleKey"文件复制到hardware中。

步骤5:在"system"中新建"pwm"文件夹,并新建"pwm.c"和"pwm.h"文件。

步骤5:工程组文件中添加"led.c"和"led.h"文件。

步骤5:工程组文件中添加"pwm.c"和"pwm.h"文件。

步骤6:目标选项添加添加头文件路径。

2、函数编辑

(1)主函数编辑

实现了呼吸灯效果的控制。在主函数中,通过调用各种初始化函数,包括延时、USART通信、LED初始化等,对系统进行了初始化设置。然后进入一个无限循环中,在循环中通过递增递减控制LED的PWM值,实现呼吸灯效果。定时器TIM2被用来产生PWM信号,而led0pwmval则控制PWM信号的占空比。

步骤1:端口初始化准备

c 复制代码
	//函数初始化,端口准备
	uint16_t led0pwmval=0;
	uint8_t dir=1;	
	delay_init();                   //启动滴答定时器
    usart1_init(9600);              //USART1初始化
	LED_Init();                     //板载LED初始化
	ExpLEDInit();                   //开发板LED初始化
	SystemTinerInit(1000-1,7200-1); //系统时间初始化 定时100ms
    PwmInit(1899, 0);               //不分频。PWM频率=72000000/900=80Khz 
	

步骤2:实现一个简单的计时器,并在每秒打印一次计时信息。利用LED状态的改变来指示系统正在运行。

c 复制代码
while(1) 
	{
      delay_ms(40);                 // 10毫秒延时,控制呼吸灯效果的速度
		
      if(dir)                       // 如果 dir 为真,则递增 led0pwmval;否则递减
          led0pwmval++;
      else
          led0pwmval--;

      if(led0pwmval > 300)          // 如果 led0pwmval 大于 300,则将 dir 置为 0,改变递增方向
          dir = 0;
      if(led0pwmval == 0)           // 如果 led0pwmval 等于 0,则将 dir 置为 1,改变递减方向
          dir = 1;
		
      // 设置定时器 TIM2 的比较值,控制 PWM 信号的占空比
      TIM_SetCompare2(TIM2, led0pwmval);      
   }

(2)USART1初始化函数(usart1_init())

配置了 PA9 为复用推挽输出,用于 USART1 的 TXD,并配置了 PA10 为浮空输入,用于 USART1 的 RXD。并配置了 USART1 的参数,包括波特率、数据位长度、停止位数、校验位、硬件流控制和工作模式。

c 复制代码
/*********************************************************************
 @Function  : USART1初始化
 @Parameter : bound : 波特率 
 @Return    : N/A
**********************************************************************/   	
void usart1_init(uint32_t bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;             										          // 定义 GPIO 初始化结构体
    USART_InitTypeDef USART_InitStructure;            										          // 定义 USART 初始化结构体
    NVIC_InitTypeDef NVIC_InitStructure;              										          // 定义 NVIC 初始化结构体

    /* 时钟使能:启用 USART1 和 GPIOA 的时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    /* 引脚复用配置 */  
    // 配置 PA9 为复用推挽输出,用于 USART1 的 TXD
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   		                             // 设置 GPIO 端口
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                // 设置 GPIO 速度
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 								 // 设置 GPIO 模式为复用推挽
    GPIO_Init(GPIOA, &GPIO_InitStructure);          							     // 初始化 GPIO

    // 配置 PA10 为浮空输入,用于 USART1 的 RXD
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                                      // 设置 GPIO 端口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                           // 设置 GPIO 模式为浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                          // 初始化 GPIO

    /* NVIC 中断配置 */ 
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                               // 设置中断通道为 USART1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;                       // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                              // 设置子优先级为3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                 // 使能中断通道
    NVIC_Init(&NVIC_InitStructure);                                                 // 初始化 NVIC

    /* USART1 配置 */ 
    USART_InitStructure.USART_BaudRate = bound;                                     // 设置波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     // 设置数据位长度为8位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          // 设置停止位为1位
    USART_InitStructure.USART_Parity = USART_Parity_No;                             // 设置校验位为无校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 设置硬件流控制为无
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 // 设置工作模式为接收和发送
    USART_Init(USART1, &USART_InitStructure);                                       // 初始化 USART1

		/*中断配置*/
		USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                                //开接受中断 
		USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);                                //开空闲中断
		USART_ITConfig(USART1,USART_IT_TXE,ENABLE);                                 //开发送中断	
		USART_Cmd(USART1, ENABLE);                                                  //启用USART1
		USART_DataTypeStr.Usart_Tc_State = SET;	                                    //置位发送允许标志	      
}

(3)USART数据发送函数( USART1_Send_Data())

初始化PD14端口,并为推挽输出。

c 复制代码
/*********************************************************************
 @Function  : USART数据发送函数
 @Parameter : Data 	 :要发送的数据缓存.
							Lenth  :发送长度
 @Return    : 发送状态   1 :失败   0 :成功
**********************************************************************/
char USART1_Send_Data(char* Data,uint8_t Lenth) 
{
	uint8_t uNum = 0;
	if(USART_DataTypeStr.Usart_Tc_State == 1)                       //判断发送标志位是否置1
	{
		USART_DataTypeStr.Usart_Tc_State = 0;                       //将发送标志位清零,表示数据已经成功放入缓存,等待发送
		USART_DataTypeStr.Usart_Tx_Len = Lenth;                     //获取需要发送的数据的长度       
	  for(uNum = 0;uNum < USART_DataTypeStr.Usart_Tx_Len;uNum ++)   //将需要发送的数据放入发送缓存
	  {
		  USART_DataTypeStr.Usart_Tx_Buffer[uNum] = Data[uNum];
	  }
    USART_ITConfig(USART1,USART_IT_TXE,ENABLE);			            //数据放入缓存后打开发送中断,数据自动发送
	}
	return USART_DataTypeStr.Usart_Tc_State;                        //返回放数据的状态值,为1表示发送失败,为0表示发送成功了
}

(4)USART数据发送函数( USART1_IRQHandler())

c 复制代码
/*********************************************************************
 @Function  : USART1中断服务函数
 @Parameter : N/A 
 @Return    : N/A
**********************************************************************/
void USART1_IRQHandler(void)                
{
	 uint8_t Clear = Clear;                                                                           // 定义清除标志的变量,并初始化为自身
	static uint8_t uNum = 0;                                                                          // 静态变量,用于循环计数
	 
  if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)                                                // 判断读数据寄存器是否为非空
  {
    USART_ClearFlag(USART1, USART_IT_RXNE);                                                           // 清零读数据寄存器,其实硬件也可以自动清零
    USART_DataTypeStr.Usart_Rx_Buffer[USART_DataTypeStr.Usart_Rx_Num ++] = \
		(uint16_t)(USART1->DR & 0x01FF);                                                              // 将接收到的数据存入接收缓冲区
		(USART_DataTypeStr.Usart_Rx_Num) &= 0xFF;                                                     // 防止缓冲区溢出
  } 
	
	else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)   // 检测空闲
	{
	  Clear = USART1 -> SR;                                                                         // 读SR位
		Clear = USART1 -> DR;                                                                       // 读DR位,
	  USART_DataTypeStr.Usart_Rx_Len = USART_DataTypeStr.Usart_Rx_Num;                              // 获取数据长度
		for(uNum = 0; uNum < USART_DataTypeStr.Usart_Rx_Len; uNum ++)          
		{
				USART_DataTypeStr.Usart_Rx_Data[uNum] = USART_DataTypeStr.Usart_Rx_Buffer[uNum];      // 将接收到的数据复制到接收数据缓冲区
		}
		USART_DataTypeStr.Usart_Rx_Num = 0;                                                           // 清空接收计数器
		USART_DataTypeStr.Usart_Rc_State = 1;                                                         // 数据读取标志位置1,读取串口数据
	}
	
	if(USART_GetITStatus(USART1,USART_IT_TXE) != RESET)                                                  // 判断发送寄存器是否为非空
  {
		USART1->DR = \
		((USART_DataTypeStr.Usart_Tx_Buffer[USART_DataTypeStr.Usart_Tx_Num ++]) & (uint16_t)0x01FF);    // 发送数据
		(USART_DataTypeStr.Usart_Tx_Num) &= 0xFF;                                                       // 防止缓冲区溢出
    if(USART_DataTypeStr.Usart_Tx_Num >= USART_DataTypeStr.Usart_Tx_Len)
    {   
			USART_ITConfig(USART1,USART_IT_TXE,DISABLE);                                                // 发送完数据,关闭发送中断
			USART_DataTypeStr.Usart_Tx_Num = 0;                                                         // 清空发送计数器
			USART_DataTypeStr.Usart_Tc_State = 1;                                                       // 发送标志置1,可以继续发送数据了
    } 		
	}
	
}

(5)系统时间初始化函数( SystemTinerInit())

Tout=((arr+1)*(psc+1))/Ft us,Ft=定时器工作频率,单位:Mhz;初始化TIM3定时器,配置定时器的周期值、预分频值、计数模式等参数,并使能定时器及其中断

c 复制代码
/*********************************************************************
 @Function  : 系统时间初始化
 @Parameter : arr:自动重装值。
							psc:时钟预分频数
 @Return    : N/A
 @Read 			:Tout=((arr+1)*(psc+1))/Ft us,Ft=定时器工作频率,单位:Mhz
**********************************************************************/
void SystemTinerInit(uint16_t arr, uint16_t psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;               // 定义TIM基本参数结构体

    NVIC_InitTypeDef NVIC_InitStructure;                         // 定义中断优先级配置结构体

    /* 时钟使能 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);         // 使能TIM3时钟

    /* TIM配置 */
    TIM_TimeBaseStructure.TIM_Period = arr;                      // 设置定时器的周期值
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                   // 设置定时器的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;      // 设置时钟分频因子为1
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 设置计数模式为向上计数
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);              // 初始化TIM3定时器

    /* 允许中断 */
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);                   // 使能TIM3更新(溢出)中断

    /* NVIC 配置 */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;              // 设置TIM3中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    // 设置TIM3中断的抢占优先级为0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;           // 设置TIM3中断的子优先级为3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              // 使能TIM3中断通道
    NVIC_Init(&NVIC_InitStructure);                              // 初始化NVIC

    /* 使能TIMx */
    TIM_Cmd(TIM3, ENABLE);                                       // 使能TIM3定时器
}

(6)等待计时函数( WaitTimerOut())

定时器超时检测功能,根据传入的参数 gTimer 和系统时钟计数器,判断定时器是否超时,并返回相应的状态。

c 复制代码
/*********************************************************************
 @Function  : 等待计时
 @Parameter : gTimer :等待时间,100ms一个单位
 @Return    : 1表示超时,0表示未超时
**********************************************************************/
uint8_t WaitTimerOut(uint32_t gTimer)
{	
	uint32_t GTr = 0;                         // 定义变量用于存储定时器剩余时间

	
	if(gTimer==0) return 1;                   // 如果等待时间为0,则直接返回1,表示不等待

	
	GTr = SystemTimer % gTimer;	              // 计算定时器剩余时间

	
	if((GTr==0) && (!Rti) && (Gti != gTimer)) // 如果定时器剩余时间为0,且上次未检测到超时,并且当前定时器时间不等于上次记录的时间
	{ 
		Rti=1;                                // 设置标志表示检测到定时器超时
		Gti = gTimer;                         // 更新记录的定时器时间
		return 1;                             // 返回1表示超时
	}
	
	else if((GTr!=0) && (Rti))                // 如果定时器剩余时间不为0,且上次检测到超时,则将标志置为0
		Rti=0;


	if(!GetTimer) GetTimer = SystemTimer;	  // 如果记录定时器开始时间为0,则将其设置为当前系统时间

	
	if(SystemTimer - GetTimer == gTimer)      // 如果当前系统时间减去记录的定时器开始时间等于设定的等待时间,则返回1表示超时
	{ 
		GetTimer = 0;                         // 将记录的定时器开始时间清零,准备下一次记录
		return 1;                             // 返回1表示超时
	}

	return 0;                                 // 返回0表示未超时
}

(7)系统时间定时器中断服务函数( TIM3_IRQHandler())

实现TIM3定时器的中断服务程序,每次定时器溢出时,增加 SystemTimer 计数值,并在计数到60时归零,同时清除中断标志位。

c 复制代码
/*********************************************************************
 @Function  : 系统时间定时器中断服务函数
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void TIM3_IRQHandler(void)   
{	
  // 检查定时器更新中断是否触发
	if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) // 溢出中断
	{
		SystemTimer++;                                // 系统时间计数器加1

		if(SystemTimer == 60)	                        // 如果系统时间计数器达到60,则重置为0,并且清零记录的定时器开始时间
		{	
		    SystemTimer = 0;
			GetTimer = 0;
		}
	}
  // 清除定时器更新中断标志位
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);     // 清除中断标志位
}

(8)获取系统计时时间函数( GetSystemTimer())

c 复制代码
/*********************************************************************
 @Function  : 获取系统计时时间
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
uint32_t GetSystemTimer(void)
{
   return SystemTimer;
}

(9)外部中断4初始化函数( EXTIX_Init())

c 复制代码
/*********************************************************************
 @Function  : 外部中断4初始化
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void EXTIX_Init(void)
{
 	EXTI_InitTypeDef EXTI_InitStructure;                      // 定义外部中断配置结构体
 	NVIC_InitTypeDef NVIC_InitStructure;                      // 定义中断控制器配置结构体
  /*时钟使能*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	      // 使能 AFIO 时钟,用于配置外部中断的映射
  /*中断线配置*/   
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource4); // 配置外部中断线,将 PC4 映射到外部中断4
  EXTI_InitStructure.EXTI_Line = EXTI_Line4;	              // 设置外部中断线为 EXTI4
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	      // 设置外部中断模式为中断模式
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;     // 设置触发方式为下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;                   // 使能外部中断线
  EXTI_Init(&EXTI_InitStructure);	 	                      // 初始化外部中断配置
	/*NVIC配置*/
  NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;	          // 设置中断向量为外部中断4
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;// 设置抢占优先级为2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;       // 设置子优先级为3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	          // 使能外部中断4
  NVIC_Init(&NVIC_InitStructure);                             // 初始化中断控制器配置
	/*关闭蜂鸣器*/
	beep = 0;                                                 // 初始化蜂鸣器状态为关闭
}

(10)外部中断4服务函数( EXTI4_IRQHandler())

c 复制代码
/*********************************************************************
 @Function  : 外部中断4服务程序
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void EXTI4_IRQHandler(void)
{
	delay_ms(10);//消抖
	if(DK1==0)				 
		beep =!beep;	
	EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位  
}

(11)窗口看门狗初始化函数(IWDG_Init())

c 复制代码
/*********************************************************************
 @Function  : 初始化窗口看门狗 	                                      
 @Parameter : tr   : T[6:0],计数器值 
							wr   : W[6:0],窗口值 
							fprer: 分频系数(WDGTB),仅最低2位有效
 @Return    : N/A    
 @Read      : Fwwdg=PCLK1/(4096*2^fprer).
**********************************************************************/
void WWDG_Init(uint8_t tr,uint8_t wr,uint32_t fprer)
{ 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //WWDG时钟使能

	WWDG_CNT=tr&WWDG_CNT;                                //初始化WWDG_CNT.   
	WWDG_SetPrescaler(fprer);                            //设置IWDG预分频值

	WWDG_SetWindowValue(wr);                             //设置窗口值

	WWDG_Enable(WWDG_CNT);	                             //使能看门狗 ,	设置 counter .                  

	WWDG_ClearFlag();                                    //清除提前唤醒中断标志位 

	WWDG_NVIC_Init();                                   //初始化窗口看门狗 NVIC

	WWDG_EnableIT();                                   //开启窗口看门狗中断
} 

(12)喂窗口看门狗函数(WWDG_IRQHandler())

c 复制代码
/*********************************************************************
 @Function  : 重设置WWDG计数器的值 	
 @Parameter : cnt : 计数器值 
 @Return    : N/A
**********************************************************************/
void WWDG_Set_Counter(uint8_t cnt)
{
    WWDG_Enable(cnt);                                  //使能看门狗 ,	设置 counter .	 
}

(13)窗口看门狗中断配置函数(WWDG_NVIC_Init())

c 复制代码
/*********************************************************************
 @Function  : 窗口看门狗中断配置	
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void WWDG_NVIC_Init(void)
{

    NVIC_InitTypeDef NVIC_InitStructure;                        // 定义 NVIC_InitTypeDef 结构体变量 

    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;             // WWDG中断

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   // 抢占2,子优先级3,组2

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;          // 抢占2,子优先级3,组2

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // 设置 NVIC_InitTypeDef 结构体变量

    NVIC_Init(&NVIC_InitStructure);                             //初始化 NVIC
}

(14)喂窗口看门狗函数(WWDG_IRQHandler())

c 复制代码
/*********************************************************************
 @Function  : 喂窗口看门狗 	
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void WWDG_IRQHandler(void)
{

    WWDG_SetCounter(WWDG_CNT);	     //当禁掉此句后,窗口看门狗将产生复位
  
	WWDG_ClearFlag();	            //清除提前唤醒中断标志位
  
	LED1=!LED1;		                //LED状态翻转
}

(15)PWM初始化函数(PwmInit())

c 复制代码
/*********************************************************************
 @Function  : PWM初始化
 @Parameter : arr:自动重装值。
              psc:时钟预分频数
 @Return    : N/A
 @Read      :Tout=((arr+1)*(psc+1))/Ft us,Ft=定时器工作频率,单位:Mhz
**********************************************************************/
void PwmInit(uint16_t arr,uint16_t psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;                                      // 定义GPIO初始化结构体变量
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;                           // 定义定时器基本配置结构体变量
    TIM_OCInitTypeDef  TIM_OCInitStructure;	                                  // 定义定时器输出比较模式配置结构体变量
    
    /* 时钟使能 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);                      // 使能TIM2时钟	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); // 使能GPIOA时钟和复用功能时钟  
    
    /* 引脚配置 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                                 // TIM2_CH2->PA1
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                           // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                    // 初始化GPIOA
    
    /* TIM配置 */ 
    TIM_TimeBaseStructure.TIM_Period = arr;                                   // 自动重装载值
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                                // 预分频值 
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;               // TIM向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);                           // 根据配置的结构体初始化TIM2	
    
    /* PWM配置 */ 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                         // TIM脉冲宽度调制模式2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;             // 比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                 // TIM输出比较极性高
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);                                  // 初始化TIM2的通道2
    
    /* 使能TIM3 CCR2 */ 
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);                         // 使能TIM2的通道2的预装载
    
    /* 使能TIM3 */ 
    TIM_Cmd(TIM2, ENABLE);                                                   // 使能TIM2
}

3、宏定义

步骤1:主函数添加所需的头文件,主源文件部分报错消失

c 复制代码
#include "system_config.h"
#include "stm32f10x_tim.h"

//头文件包含
/*************SYSTEM*****************/
/*#include ".\sys\sys.h"*/
#include ".\delay\delay.h"
#include ".\usart\usart.h"
#include ".\timer\timer.h"
#include ".\pwm\pwm.h"

/***********Hardweare***************/
#include "led.h"

步骤2:添加中断源文件所需的头文件

c 复制代码
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include ".\pwm\pwm.h"

步骤3:添加串口通信宏定义

c 复制代码
#define USART_RX_LEN  200               // 接收缓冲区最大长度
#define USART_TX_LEN  200               // 发送缓冲区最大长度
#define UART_NUM      10                // 串口结构体最大对象数量

步骤4:添加函数声明

c 复制代码
void usart1_init(uint32_t bound);
extern USART_DataTypeDef USART_DataTypeStr; 
char USART1_Send_Data(char* Data,uint8_t Lenth);

步骤5:添加数据类型和宏的头文件

c 复制代码
//定义串口数据结构体
typedef struct USART_DataType 
{
    uint8_t Usart_Rx_Len;          // 接收缓冲区长度
    uint8_t Usart_Tx_Len;          // 发送缓冲区长度
    uint8_t Usart_Rx_Num;          // 接收数据计数
    uint8_t Usart_Tx_Num;          // 发送数据计数
    uint8_t Usart_Rc_State;        // 接收状态标志位
    uint8_t Usart_Tc_State;        // 发送状态标志位
    char Usart_Rx_Buffer[USART_RX_LEN]; // 接收缓冲区
    char Usart_Tx_Buffer[USART_TX_LEN]; // 发送缓冲区
    char Usart_Rx_Data[USART_RX_LEN];   // 接收数据
    char Usart_Tx_Data[USART_TX_LEN];   // 发送数据
} USART_DataTypeDef;

步骤6:定义一个串口数组变量

c 复制代码
USART_DataTypeDef USART_DataTypeStr={0};

定时器宏定义

步骤1:创建一个宏定义保护

c 复制代码
#ifndef __TIMER_H
#define __TIMER_H

#endif

步骤2:添加函数声明

c 复制代码
void SystemTinerInit(uint16_t arr,uint16_t psc);//系统时间初始化函数
uint32_t GetSystemTimer(void);                  //获取系统计时时间函数
uint8_t WaitTimerOut(uint32_t gTimer);          //等待计时函数

步骤3:添加数据类型和宏的头文件

c 复制代码
#include <stdint.h> 

中断宏定义

步骤1:创建一个宏定义保护

c 复制代码
#ifndef __TIMER_H
#define __TIMER_H

#endif

步骤2:添加函数声明

c 复制代码
void EXTIX_Init(void);	

步骤3:添加数据类型和宏的头文件

c 复制代码
#include <stdint.h> 

窗口看门狗宏定义

步骤1:创建一个宏定义保护

c 复制代码
#ifndef _WWDG_H
#define _WWDG_H



#endif

步骤2:添加函数声明

c 复制代码
void WWDG_Init(uint8_t tr,uint8_t wr,uint32_t fprer);
void WWDG_Set_Counter(uint8_t cnt);       
void WWDG_NVIC_Init(void);

步骤3:添加数据类型和宏的头文件

c 复制代码
#include <stdint.h> 

PWM脉宽输入应用宏定义

步骤1:创建一个宏定义保护

c 复制代码
#ifndef __PWM_H_
#define __PWM_H_



#endif

步骤2:添加函数声明

c 复制代码
void PwmInit(uint16_t arr,uint16_t psc);

步骤3:添加数据类型和宏的头文件

c 复制代码
#include <stdint.h> 

4、知识链接

(1)pwm基础知识

PWM(脉冲宽度调制)是一种用于控制模拟电子信号的技术,通过在一定时间内改变信号的脉冲宽度来控制其平均功率。PWM常用于模拟电子系统中的电机速度控制、LED亮度调节、音频信号生成等应用。它的工作原理是在一个周期性的脉冲信号中,通过控制高电平(ON)和低电平(OFF)的时间比例来控制输出信号的平均电压值。因此,通过调节PWM信号的占空比(高电平时间与周期时间的比值),可以实现对输出信号的精确控制,从而达到对被控制设备的精确控制的目的。

(2)PWM计数通俗理解

PWM技术有效地解决了数字系统无法直接控制模拟设备的痛点,为各种应用提供了一种灵活、精确且经济的控制方法。

5、工程测试

相关推荐
国科安芯11 分钟前
火箭传感器控制单元的抗辐照MCU选型与环境适应性验证
单片机·嵌入式硬件·架构·risc-v·安全性测试
-Springer-1 小时前
STM32 学习 —— 个人学习笔记5(EXTI 外部中断 & 对射式红外传感器及旋转编码器计数)
笔记·stm32·学习
LS_learner1 小时前
树莓派(ARM64 架构)Ubuntu 24.04 (Noble) 系统 `apt update` 报错解决方案
嵌入式硬件
来自晴朗的明天2 小时前
16、电压跟随器(缓冲器)电路
单片机·嵌入式硬件·硬件工程
钰珠AIOT2 小时前
在同一块电路板上同时存在 0805 0603 不同的封装有什么利弊?
嵌入式硬件
代码游侠2 小时前
复习——Linux设备驱动开发笔记
linux·arm开发·驱动开发·笔记·嵌入式硬件·架构
代码游侠13 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg200515 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT17 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件