说明:本例子采用的是AVR128单片机的定时器T0,利用CTC模式产生的PWM,通过按键可以调节PWM的占空比,其中可调的频率范围是15K--5M(但是高达5M的时候由于没有外加的滤波稳性电路,所以方波看上去会有毛刺)。
在用示波器调试的时候我老是调不了占空比,也就是更新不了OCR0的值,后来查阅AVR128的技术文档发现,在T0的CTC模式下面更新OCR0的值是要在比较匹配中断的服务程序里面。希望大家以后写的时候要注意更新你的寄存器的时间!
代码如下:(使用内部晶振8M)
编译环境: ICCAVR
#include<iom128v.h>
#include<macros.h>
#define uint unsigned int
#define uchar unsigned char
#define S5 4
#define S6 5
#define S7 6
#define S8 7 //按键定义
#define KEY_PORT PORTD //按键端口
#define KEY_PIN PIND
#define KEY_DDR DDRD
#define BUZZ_PORT PORTG
#define BUZZ_PIN PING
#define BUZZ_DDR DDRG //蜂鸣器端口
#define SPK 4 //蜂鸣器
void delay_1ms(void) //1ms延时函数
{
unsigned int i;
for (i=0;i<1140;i++);
}
void delay_nms(unsigned int n) //N ms延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1ms();
}
void Key_init(void) //键盘初始化
{
KEY_DDR &=~ (1<<S5)|(1<<S6)|(1<<S7)|(1<<S8);
KEY_PORT |= (1<<S5)|(1<<S6)|(1<<S7)|(1<<S8);
}
void get_key(void) //按键检测
{
switch(KEY_PIN&0xf0)
{
case 0xE0: {OCR0++;Beep();break;}
case 0xD0: {OCR0++;Beep();break;}
case 0xB0: {OCR0--;Beep();break;}
case 0x70: {OCR0--;Beep();break;} //改变OCR0的值
default: break;
}
}
void Buzz_init(void) //蜂鸣器=初始化
{
BUZZ_DDR |= (1<<SPK);
BUZZ_PORT &=~ (1<<SPK);
}
void Beep(void) //蜂鸣器响
{
BUZZ_PORT |= (1<<SPK);
delay_nms(100);
BUZZ_PORT &=~ (1<<SPK);
delay_nms(50);
}
void timer0_init(void)
{
TCCR0 = 0X00;
OCR0 = 0XE7; //8位的定时计数器的初值设定为0x55
TCNT0 = 0; //计数器
TCCR0 = 0X19; //设置为CTC模式,不采取分频
}
void port_init(void)
{
DDRE = 0xFF;
PORTE = 0xFF;
PORTB |= BIT(PB4); //比较匹配输出口打开
DDRB |= BIT(PB4);
}
void main(void)
{
CLI(); //禁止所有中断
timer0_init();
port_init();
Buzz_init();
Key_init();
TIMSK = 0X02; //T0的比较溢出中断使能
SEI(); //开启总中断
while(1); //等待比较匹配中断
}
#pragma interrupt_handler timer1_comA_isr:16 //定时器T0比较匹配中断服务程序
void timer1_comA_isr(void)
{
get_key();
}
zenghao616_997442595 2011-3-1 12:12
用户306685 2011-3-1 11:39