s5p6818PWM驱动蜂鸣器实验
一, PWM 概念
PWM (Pulse Width Modulation ):脉冲宽度调制解调器。
阈值:就是输出的 PWM 中,高饱和保持的时间与该PWM 的时钟周期的时间之比。
脉冲:方波
宽度调制:方波的周期和占空比可以调节。
占空比:一个周期内,高电平占整个周期的百分比。
比如:高电平0.5s 低电平0.5 周期 1s 占空比:50%
蜂鸣器种类:
1)有源蜂鸣器:
蜂鸣器内部有一个震荡源,蜂鸣器内部有电流流过蜂鸣器发声,
没有电流流过蜂鸣器不发声。
2)无源蜂鸣器:
蜂鸣器内部没有震荡源,
通过编程的方式让蜂鸣器以一定的频率震荡蜂鸣器即可发声,
否则不发声。
F5P6818是有缘蜂鸣器
二, PWM 应用
它是利用调制的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛的测量,通信,功率控制与变换等许多领域。脉冲宽度调制( PWM )是一种对模拟信号通过改进的计数器的使用,方波的替代被调制变成对一个具体模拟信号的可以进行编码。
常见应用有:电机控制, DAC 输出等。
三, S5P6818PWM 概述
S5P6818 有5 路32 位PWM 定时器。这些定时器为ARM 子系统提供外部中断。另外,计时器0,1,2,3,包括PWM 功能并且驱动外部I / O 引脚。PWM 定时器0 有一个Timer4 是外部定时器没有输出指针。可选的死区产生器,支持驱动大电流设备的能力。
定时器使用 APB-PCLK 作为时钟源。定时器0 和1 共享一个8 位可编程的预分频器,位PCLK 提供第一级分频。定时器2,3 和4 共享另外一个8 位预分频器。每个定时器有自己私有的时钟分配器,提供一个二级时钟分频(分频数值 1,2,4,8,16 )。
每个定时器都有一个 32 位递减计数器,通过计时器时钟驱动。递减计数器初始值加载从TCNTB0 。当递减计数器到达0 时,定时器中断请求产生并通知CPU ,定时器操作完成。当定时器递减计数器到达0 时,相对应的TCNTBn 中的值自动加载到递减计数器中开始下一个周期。然而,如果计时器停止,例如,通过清除计时器TCONn 的使能位,在定时器运行时,TCNTBn 中的值不在加载到定时器中。
PWM 功能使用TCMPB0寄存器的值。定时器控制逻辑改变输出并转换到定时器控制逻辑。因此,比较寄存器决定PWM 输出的高电平时间。
四, S5P6818 框图
五, S5P6818 PWM 控制蜂鸣器
硬件电路图:
六,相关寄存器分析
1.分析芯片手册
2.分析GPIO章节–GPIOxALTFN0
设置GPIOC14引脚为PWM功能, GPIOCALTFN0[29:28] = 10
基本地址:0xC001_C000h(PWM)
地址=基地址+ C020h,复位值= 0x0000_0000
3.分析PWM章节
4.分析PWM章节–TCFG0
基本地址:0xC001_8000h(PWM)
地址=基地址+ 0x00h,复位值= 0x0000_0101
Timer Input Clock Frequency = PCLK/({prescaler value + 1})/{divider value}
{prescaler value} = 1 to 255
{divider value} = 1, 2, 4, 8, 16
Dead Zone Length = 0 to 254
定时器输入时钟频率 = PCLK /({预分频器值+ 1})/ {分频器值}
{预分频器值} = 1至255
{divider value} = 1,2,4,8,16
死区长度= 0至254
**注意:**如果将死区长度设置为“ n”,则实际死区长度为“ n +1”(n = 0至254)。PCLK的源时钟为BLK_MIF中的BUS_DPLL
5.分析PWM章节–TCFG1
基本地址:0xC001_8000h(PWM)
地址=基地址+ 0x40h,复位值= 0x0000_0000
设置PWM定时器的二级分频值
选择PWM定时器2的复用输入
0000 = 1/1 (一分频)
0001 = 1/2 (二分频)
0010 = 1/4(四分频)
0011 = 1/8 (8分频)
0100 = 1/16 (16分频)
0101 =外部TCLK1
0110 =外部TCLK1
0111 =外部TCLK1
6.分析PWM章节–TCON
TCON:PWM定时器控制寄存器
Base Address: 0xC001_8000h (PWM)
Address = Base Address + 0x08h, Reset Value = 0x0000_0000
基本地址:0xC001_8000h(PWM)
地址=基地址+ 0x80h,复位值= 0x0000_0000
TCON[15]:定时器2的自动重载的开和关
0:只加载一次 1:自动重载 将TCNTBn中的值加载的递减计数器中
TCON[14]:定时器2输出翻转的开和关
0:关闭翻转 1:打开翻转 PWM方波的初始状态
TCON[13]:定时器2的手动更新位
0:关闭手动更新 1:打开手动更新 给TCNTB和TCMPB赋值时需要手动更新
TCON[12]:定时器2的使能和禁止位
0:停止PWM定时器 1:开启PWM定时器
7.分析PWM章节–TCNTB2
Base Address: 0xC001_8000h (PWM)
Address = Base Address + 0x24h, Reset Value = 0x0000_0000
基地址:0xC001_8000h(PWM)
地址 = 基地址 + 0x24h,复位地址0x0000_0000
8.分析PWM章节–TCMPB2
Base Address: 0xC001_8000h (PWM)
Address = Base Address + 0x28h, Reset Value = 0x0000_0000
基地址:0xC001_8000h (PWM)
地址 = 基地址 + 0x28h,复位地址 = 0x0000_0000
7.编写代码
pwm.c
#include "pwm.h"
void hal_pwm_init()
{
//1.设置GPIOC14引脚为PWM功能 GPIOCALTFN0[29:28] = 0b10
GPIOC.ALTFN0 &= ~(3 << 28);
GPIOC.ALTFN0 |= (2 << 28);
//2.设置对PCLK时钟的一级分频值,进行250分频 TCFG0[15:8] = 249
PWM.TCFG0 &= ~(0xFF << 8);
PWM.TCFG0 |= (249 << 8);
//3.设置对PCLK时钟的二级分频值,进行2分频 TCFG1[11:8] = 0b0001
PWM.TCFG1 &= ~(0xF << 8);
PWM.TCFG1 |= (1 << 8);
}
void hal_pwm_switch(int cnt, int cmp, pwm_stu st)
{
if (st == ON){
hal_pwm_init();
//4.设置TCNTB2的初始值,确定PWM方波的最终周期
//设置置TCNTB2 = 300-1 PWM方波的频率为1000Hz
PWM.TCNTB2 = cnt;
//5.设置TCMPB2的初始值值,确定PWM方波的占空比
// 设置TCMPB2 = 150-1
PWM.TCMPB2 = cmp;
//6.打开电平翻转功能 TCON[14] = 0b1
PWM.TCON |= (1 << 14);
//7.第一个周期是开启手动加载TCNTB2和TCMPB2到递减计数器中
//TCON[13] = 0b1
PWM.TCON |= (1 << 13);
//8.开启自动加载 TCON[15] = 0b1
PWM.TCON |= (1 << 15);
//9.关闭手动加载 TCON[13] = 0b0
PWM.TCON &= ~(1 << 13);
//10.使能PWM定时器2 TCON[12] = 0b1
PWM.TCON |= (1 << 12);
// 到此PWM控制器就可以产生一个方波,通过GPIOC14引脚输出。
} else {
PWM.TCON &= ~(1 << 15);
PWM.TCON &= ~(1 << 12);
GPIOC.ALTFN0 &= ~(3 << 28);
GPIOC.ALTFN0 |= (1 << 28);
GPIOC.OUTENB |= (1 << 14);
GPIOC.OUTENB &= (~(1 << 14));
}
}
pwm.h
#ifndef __PWM_H__
#define __PWM_H__
#include "s5p6818_pwm.h"
typedef enum {
OFF = 0,
ON,
}pwm_stu;
void hal_pwm_init();
void hal_pwm_switch(int cnt, int cmp, pwm_stu st);
#endif // __PWM_H__
s5p6818_pwm.h
#ifndef ___S5P6818_PWM_H_
#define ___S5P6818_PWM_H_
/************* PWM ******************/
typedef struct {
uint32 TCFG0;
uint32 TCFG1;
uint32 TCON;
uint32 TCNTB0;
uint32 TCMPB0;
uint32 TCNTO0;
uint32 TCNTB1;
uint32 TCMPB1;
uint32 TCNTO1;
uint32 TCNTB2;
uint32 TCMPB2;
uint32 TCNTO2;
uint32 TCNTB3;
uint32 TCMPB3;
uint32 TCNTO3;
uint32 TCNTB4;
uint32 TCNTO4;
uint32 TINT_CSTAT;
}pwm;
#define PWM (* (volatile pwm *)0xC0018000)
#endif
main.c
#include "pwm.h"
int main()
{
hal_led_init();
hal_pwm_init();
while(1)
{
printf("pwm test!\n");
hal_pwm_switch(299, 149, ON);
delay_ms(1000);
hal_pwm_switch(299, 149, OFF);
delay_ms(1000);
}
return 0;
}
delay.c
#include "delay.h"
void delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i = 0; i < ms; i++)
for(j = 0; j < 1800; j++);
}
delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void delay_ms(unsigned int ms);
#endif //__DELAY_H__
8.下载调试。
下载调试请看这个帖子最后调试步骤。