1. pwm脉宽调制器
脉宽调制器: 一种硬件设备, 用于 动态调制 方波 的 一些属性, 方波的周期,频率,占空比
占空比? : 有效电平占 整个周期的比值
可以使用PWM 控制功率, 控制频率 用于 开关电源 或 逆变器
1.1 原理
PWM原理: 如图所示
本质就是一个定时器:
由原理可知:
输出波形的 频率 = 总线时钟 / (分频值+1) / 重载值 ;
输出波形的 占空比 = 比较值 / 重载值
1.2 pwm标准时钟的频率
100Mhz
2. 实验:使用pwm驱动蜂鸣器 以500hz 占空比50% 发出声响
输出定时器信号的 频率 = 总线时钟 /固定分频/ (分频值+1) / 重载值 ;
占空比 = 比较寄存器/重载值
实现功能 输出一个 500hz 方波 占空比 50%
500hz = 100M / (分频值+1) / 重载值 ; //这里不固定分频
500hz = 100M / (99+1) / 重载值 ;
500hz = 1M / 重载值 ;
重载值 = 2K
0.5 = 比较值 / 重载值 ;
比较直 = 1K
2.1 看原理图
1292页
我们走红色线路
1. 硬件 : 蜂鸣器
2. 电路图
芯片管脚 PD0_0 ---- XpwmTOUT0 PWM输出
3. pwm控制器 芯片手册
5个 pwm
0-3 有 PWM 输出
0 pwm 有 死区控制
4 pwm 没有输出
死区控制: 主要用于控制 半H桥电路 或 全H桥电路 有用
控制器 结构框图 1292 页
2.2 配置寄存器
TCFG0 两路预分频
TCFG0 : 两路预分频 死区配置
[7:0] = 预分频
TCFG1 5路固定分频
TCFG1 : 5路 固定分频 配置
[3:0] = 0-4 分别对应 1/1 1/2 1/4 1/8 1/16
TCNTB0: PWM0 重载寄存器 32bit 0 - 2^32-1
TCMPB0: PWM0 比较寄存器
TCNTO0: PWM0 计数寄存器 只读
TCON : 总控
TCON : 总控
[4] = 0 不使能死区
[3] = 0 单次模式 1 自动重装
[2] = 1 打开输出
[1] = 1 装载 重载寄存器 比较寄存器
[0] = 1 启动pwm0
2.3 写代码
pwm_test----main.c
#include"exynos_4412.h"
#include"uart.h"
//使用pwm驱动蜂鸣器 以500hz 占空比50% 发出声响
//pwm 初始化
void pwm_init(){
//配置GPD0_0 为pwm功能
GPD0.CON = (GPD0.CON & ~(0xf<<0)) | (2<<0);
//配置pwm控制器,五路固定分频 TCFG1 [3:0] = 0 这里蛇蛇不固定分频
PWM.TCFG1 &= ~(0xf);
//两路预分频 TCFG0 [7:0] = 99 100M/(99+1) = 1M
PWM.TCFG0 = (PWM.TCFG0 & ~(0xff<<0)) | (99<<0);
//重载值
PWM.TCNTB0 = 2000;
//比较寄存器
PWM.TCMPB0 = 1000;
//配置总控
//不使能死区
PWM.TCON &= ~(1<<4);
//自动重装
PWM.TCON |= 1<<3;
//打开输出
PWM.TCON |= 1<<2;
//装载TCNTB0 TCMPB0
PWM.TCON |= 1<<1;
//关闭装载
PWM.TCON &= ~(1<<1);
//启动pwm
PWM.TCON |= 1;
}
int main()
{
int a = 100;
uart_init();
printf("hello!a=%d\r\n",a);
pwm_init();
while(1);
return 0;
}
3. 使用蜂鸣器调出音律
这里我们调制 高音即可
输出定时器信号的 频率 = 总线时钟 /固定分频/ (分频值+1) / 重载值 ;
占空比 = 比较寄存器/重载值
pwm_muisc-----main.c
#include"exynos_4412.h"
#include"uart.h"
//pwm 模拟音律播放
volatile unsigned int count = 0;//毫秒级变量
//延时 ms
void delay(unsigned short ms){
unsigned int tmp = count;//存放刚进入delay函数时 count 的数值
// while(count <= tmp+ms);//这种算法没有规避溢出问题
while(count-tmp < ms);//这种算法规避了溢出问题,不必纠结算法,用就完事了
}
//中断初始化
exit_init(){
//GIC 面向中断源
//开启总中断
ICDDCR = 1;
//配置端口中断使能
//中断模式: wdt中断 id 75
//75/32=2 75%32=11
ICDISER.ICDISER2 |= 1<<11;
//配置端口优先级 优先级设置为5
//75/4= 18 75%4=3 ---- [15:8]
ICDIPR.ICDIPR18 = (ICDIPR.ICDIPR18 & ~(0xff<<24)) | (5<<24);
//配置中断源送去哪个cpu处理 0x1表示直送cpu0
//寄存器分步格局 与ICDIPR 完全一样
ICDIPTR.ICDIPTR18 = (ICDIPTR.ICDIPTR18 & ~(0xff<<24)) | (0x1<<24);
//GIC 面向cpu
//cpu响应中断使能 =1 使能 =0 不使能
CPU0.ICCICR = 1;
//配置cpu过滤优先级
CPU0.ICCPMR = 255;
}
//中断响应,c语言入口函数,在汇编汇总调用,当irq异常触发时
void do_irq(){
//获取中断号
int id = CPU0.ICCIAR;
//根据中断id来处理对应的事件
switch(id){
case 75:
count++;
//先清除中断 源头的挂起 看门狗的中断
//写入任何值清除
WDT.WTCLRINT = 8;
//在清除GIC分配器层中断挂起 与ICDISER_CPU 结构一样 id:57
//置为1 清除
ICDICPR.ICDICPR2 |= 1<<11;
break;
}
//最后清除cpu中断挂起
//写入中断id清除对应中断挂起
CPU0.ICCEOIR = id;
}
//看门狗初始化
void dog_init(){
//预分频
WDT.WTCON = (WDT.WTCON &~(0xff<<8)) | (24<<8);
//固定分频
WDT.WTCON = (WDT.WTCON &~(0x3<<3)) | (0<<3);
//触发中断信号 [2] 时间到,是否触发中断信号 = 1 触发中断
WDT.WTCON |= 1<<2;
//重载寄存器
WDT.WTDAT = 250;
//计数寄存器
WDT.WTCNT =250;
//开启看门狗
WDT.WTCON |= 1<<5;
}
//pwm 初始化
void pwm_init(){
//配置GPD0_0 为pwm功能
GPD0.CON = (GPD0.CON & ~(0xf<<0)) | (2<<0);
//配置pwm控制器,五路固定分频 TCFG1 [3:0] = 0 这里设不固定分频
PWM.TCFG1 &= ~(0xf);
//频率 = 总线时钟 /固定分频/ (分频值+1) / 重载值 ;
//两路预分频 TCFG0 [7:0] = 99 100M/(99+1) = 1M
PWM.TCFG0 = (PWM.TCFG0 & ~(0xff<<0)) | (99<<0);
//重载值
PWM.TCNTB0 = 2000;
//比较寄存器 占空比 = 比较寄存器/重载值
PWM.TCMPB0 = 1000;
//配置总控
//不使能死区
PWM.TCON &= ~(1<<4);
//自动重装
PWM.TCON |= 1<<3;
//打开输出
PWM.TCON |= 1<<2;
//装载TCNTB0 TCMPB0
PWM.TCON |= 1<<1;
//关闭装载
PWM.TCON &= ~(1<<1);
}
//启动pwm
void pwm_start(){
//启动pwm
PWM.TCON |= 1;
}
//关闭pwm
void pwm_stop(){
//启动pwm
PWM.TCON &= ~1;
}
//改变音色
void chanage_pinlv(unsigned int hz){
//重载值
PWM.TCNTB0 = 1000000/hz;
//比较寄存器 //占空比我们设为50%
PWM.TCMPB0 = 1000000/hz/2;
//装载TCNTB0 TCMPB0
PWM.TCON |= 1<<1;
//关闭装载
PWM.TCON &= ~(1<<1);
//打开pwm
pwm_start(); //因为我们在播放音律函数时 停止了pwm 所以每次改变音色 都要重新开启pwm
}
//定义音符频率
#define H1 1046
#define H2 1175
#define H3 1318
#define H4 1397
#define H5 1568
#define H6 1760
#define H7 1976
#define ST 0
//播放音律
void play(){
chanage_pinlv(H1);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H2);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H3);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H4);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H5);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H6);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
chanage_pinlv(H7);
delay(1000);//响一秒
pwm_stop();
delay(500);//停一秒
}
int main()
{
uart_init();
printf("music!!!\r\n");
//看门狗初始化
dog_init();
//中断初始化
exit_init();
//pwm初始化
pwm_init();
//开启pwm
pwm_start();
int i=0;
while(1){
play();
delay(2000);//所有音律播放完成总体停2秒
}
return 0;
}