一:原理解析
在编写代码前,首先要明白,PWM方波是怎么产生的。
当定时器启动后,自动重载计数器中的值会自动加载到递减计数器中。递减计数器在CK_CNT时钟驱动下进行工作。每过一个时钟周期,递减计数器中的值会自动 -1。当减少到和捕获/比较寄存器中的值相同时,电平发生翻转,PWM方波信号就产生了。
二:电路分析
翻看芯片手册
由此可知:蜂鸣器引脚为TIM4_CH1
去主板上查找该引脚
可知,主板引脚为PB6
所以可知
RCC寄存器给TIM4相关控制器、GPIOB寄存器使能。由TIM4寄存器产生PWM方波信号,激活蜂鸣器。GPIOB寄存器控制蜂鸣器工作。
三:查看芯片手册,确定引脚功能
1:RCC章节分析
搜索可知,TIM寄存器,所在总线为APB1
起始地址为0x40002000
GPIO寄存器,上篇文章已经找过了,不再过多赘述
GPIOB --> AHB4总线 -->起始地址:0x50003000
RCC对GPIOB使能
即:
RCC_MP_AHB4ENSETR[1] = 1
RCC对TIM4使能
查找RCC_MP_APB1ENSETR寄存器
即为:
RCC_MP_APB1ENSETR[2] = 1
2:GPIO章节分析
GPIOx_MODER
设置PB6引脚为复用功能
GPIOx_AFRL寄存器
6号引脚,在AFRL寄存器上
但是,我们并不知道它的引脚填什么值,所以还需要再去看另一个芯片手册:《stm32mp157a》
故,选择AF2模式(回到原芯片手册)
即:
GPIOB_AFRL[27:24] = 0010
3:TIM4章节分析
工作原理最开始大致介绍,此处不再赘述,我们直接根据原理图顺序,开始寄存器分析
TIM4_PSC寄存器
分频寄存器,因为系统默认频率为209MHZ,所以,为了方便计算,我们把它设置为209-1 = 208
即
TIM4_PSC[15:0] = 208 //即0xD0
TIM4_ARR寄存器
自动重载计数器,用以设置周期时长
0~15位设置为1000
TIM4_ARR[15:0] = 1000 //0x3E8
TIM4_CCMR1寄存器
设置PWM模式
TIM4_CCMR1[16][6:4] = 0110------>设置为PWM1模式
设置预加载使能
TIM4_CCMR1[3] = 1 ------>设置预加载使能
TIM4_CCMR1[1:0] = 00 ------>设置为输出模式
TIM4_CCER寄存器
TIM4_CCER[1] = 0 //高电平
TIM4_CCER[0] = 1
TIM4_CCR 1寄存器
比较捕获寄存器,影响方波高电平占比
TIM4_CCR1[15:0] = 700
TIM4_CR1寄存器
即:
TIM4_CR1[7] = 1 ------>自动重载计数器预加载使能
TIM4_CR1[6:5] = 00 ------>设置边沿对齐模式
TIM4_CR1[4] = 1 ------>设置递减计数器
TIM4_CR1[0] = 1 ------>设置计数器使能
至此,芯片手册分析完毕
四:代码实现
把前面分析出的代码组合
本次头文件采用现成的库,封装原理可以参考鄙人上一篇文章
pwm.h
#ifndef __PWM_H__
#define __PWM_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_tim.h"
#include "stm32mp1xx_rcc.h"
//初始化
void pwm_init();
#endif
功能代码:pwm.c
#include "pwm.h"
void pwm_init()
{
/***********RCC初始化**************/
//使能GPIOB
RCC->MP_AHB4ENSETR = (0x1 << 1);
RCC->MP_APB1ENSETR = (0x1 << 2);
/*****GPIO章节初始化*****/
GPIOB->AFRL &= (~(0xf << 24));
GPIOB->AFRL |= (0x2 << 24);
//设置PB6引脚为输出模式
//GPIOB_MODER[13:12] = 0b01
GPIOB->MODER &= (~(0x3 << 12));
GPIOB->MODER |= (0x2 << 12);
/***********TMI4寄存器**************/
//TIM4_PSC寄存器
TIM4->PSC &= ~(0xffff);
TIM4->PSC |= 0xd0; //208
//TIM4_ARR寄存器 自动重载寄存器
TIM4->ARR &= ~(0xffff);
TIM4->ARR |= (0x3E8); //1000
//TIM4_CCMR1寄存器
//设置pwm1模式TIM4_CCMR1 16 [6:4] = 0110
TIM4->CCMR1 &= (~(0x1 << 16)); //16位置0
TIM4->CCMR1 &= (~(0x7 << 4)); //6~4位清零
TIM4->CCMR1 |= (0x6 << 4); //置为110
//设置预加载使能TIM4_CCMR1[3] = 1
TIM4->CCMR1 |= (0x1 << 3);
//设置为输出模式 TIM4_CCMR1[1:0] = 00
TIM4->CCMR1 &= (~(0x3 << 0));
//TIM4_CCER寄存器
//设置起始位高电平
TIM4->CCER &= (~(0x1 << 1));
//配置输出使能
TIM4->CCER |= (0x1 << 0);
//TIME4_CCR1
TIM4->CCR1 &= (~(0xffff));
TIM4->CCR1 |= (0x12c);
//TIM4_CR1寄存器
//自动承载计数器预加载使能
TIM4->CR1 |= (0x1 << 7);
//设置边沿对齐模式
TIM4->CR1 &= (~(0x3) << 5);
//设置递减计数器
TIM4->CR1 |= (0x1 << 4);
//设置计数器使能
TIM4->CR1 |= (0x1 << 0);
}