flash unsigned char char_7[8]={0x10,0x38,0x7C,0xFE,0x38,0x38,0x38,0x38}; int j=0;
unsigned char time_counter,i = 0; void display(unsigned char row) {
unsigned char i; for (i=0;i<=7;i++) {
if (row <= 7)
PORTA = char_7[row]; else
PORTA = 0; PORTC = ~(1<if (++row >= 12 ) row = 0; } }
// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void) {
display(i); if(++j>=50) {
j=0;
time_counter=1; } }
void main(void) {
PORTA=0x00; DDRA=0xFF; PORTC=0xFF; DDRC=0xFF;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 62.500 kHz
// Mode: CTC top=OCR0
// OC0 output: Disconnected
TCCR0=0x0B; TCNT0=0x00; OCR0=0x7C;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;
#asm(\"sei\")
while (1) {
display(i);
if (time_counter) {
time_counter = 0; if(++i >= 12) i=0; }
}; }
3.使用定时器的产生特定频率,输出到蜂鸣器上产生不同的音调。使用定时器产生DO RE MI
FA SO LA SI 声音,每个音长1秒。(假设 do 256 re 288 mi 320 fa 341 so 384 la 426 si 480) hz。(参考第八章例8.7的硬件电路以及软件设计,利用AVR的16位T/C1的比较匹配功能,发出不同频率的音调。)
#include flash unsigned int t[9] = {0,956,865,759,716,638,568,506,470 }; flash unsigned char d[9] = {0,105,116,132,140,157,176,198,209 }; #define Max_note 14
flash unsigned char music[Max_note] = {1,10,2,10,3,10,4,10,5,10,6,10,7,10}; unsigned char note_n; unsigned int int_n; bit play_on;
interrupt [EXT_INT1] void ext_int1_isr(void) //INT1中断服务程序 {
if (!play_on) TCCR1B = 0x09; //启动T/C1,播放音乐 }
interrupt [TIM1_COMPA] void timer1_compa_isr(void) // T/C1比较匹配中断服务程序 {
if (!play_on) {
note_n = 0; int_n = 1;
play_on = 1; //从头开始播放音乐 } else
{ //播放一个音符
if (--int_n == 0) //一个音符播放完成 {
TCCR1B = 0x08; //停止T/C1工作
if (note_n < Max_note)
{ //音乐未播完 OCR1A = t[music[note_n]]; //取下一个音符
int_n = d[music[note_n]]; //取该音符的基本节拍单位 note_n++;
int_n = int_n * music[note_n];//计算该音符的节拍值 note_n++;
TCCR1B = 0x09; //启动T/C1,播放一个音符 } else
play_on = 0; //整个音乐播放完成 }
} }
void main(void) {
PORTD=0x08; //PD5匹配输出方式,脉冲输出,驱动发声 DDRD=0x20; //PD3按键输出口,输入方式,上拉电阻有效 TCCR1A=0x40; //T/C1工作于CTC方式
TCCR1B=0x08; //OCR1A为比较寄存器,OC1A为触发取反方式 TIMSK=0x10; //允许比较匹配OC1A中断 GICR|=0x80; //外部中断初始化 MCUCR=0x08; //允许INT1中断 MCUCSR=0x00; //下降沿触发 GIFR=0x80;
#asm(\"sei\") //使能全局中断 while (1) { } }
[选作实验内容]
参考demo_8_6.c,利用T/C1的PWM方式,设计出能产生更精确的、频率为1KHz、幅值为0~5V的正弦波(提示:使用T/C1,选择工作模式10,设置ICR1=250为计数值得上限值)。 #include flash unsigned char auc_SinParam[128] = {
128,134,140,147,153,159,165,171,177,182,188,193,198,204,208,213, 218,222,226,230,233,237,240,242,245,247,249,251,252,253,254,254, 254,254,253,252,251,250,248,246,244,241,238,235,232,228,224,220, 215,211,206,201,196,191,185,179,174,168,162,156,150,144,137,131, 125,119,112,106,100,94,88,82,77,71,65,60,55,50,45,41, 36,32,28,24,21,18,15,12,10,8,6,5,4,3,2,2, 2,2,3,4,5,7,9,11,14,16,19,23,26,30,34,38,
43,48,52,57,63,68,74,79,85,91,97,103,109,116,122,128}; // 128点正弦波样本值
unsigned char x_SW = 8,X_LUT = 0;
// T/C1 溢出中断服务
interrupt [TIM1_OVF] void timer1_ovf_isr(void) {
X_LUT += x_SW; // 新样点指针 if (X_LUT > 127) X_LUT -= 128; // 样点指针调整
OCR1A = auc_SinParam[X_LUT]; // 取样点指针到比较匹配寄存器 //OCR1A+=1; }
void main(void) {
DDRD=0x08; //PD3输出方式,作为OC1A的输出口 TCCR1A=0x82;
TCCR1B=0x11; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x01; ICR1L=0xF4; OCR1AH=0x00;
OCR1AL=0x80; TIMSK=0x04;
#asm(\"sei\") // 开放全局中断
while (1) {}; }
[实验总结与思考]
1. 仔细参考书上例程8.3,回答P253页上的5个问题。 a. 普通模式下,溢出与匹配中断都允许。要实现N分频的话,则TCNT0初值设为FF-(N-1),
比较匹配OCR0设在TCNT0初值跟0xFF的之间的值,每次溢出中断都重新设置 TCNT0为FF-(N-1),输出取反;每次比较匹配中断都使输出取反,则可以实现N分频。 b. TCNT0初值为255-10=245,即为0xF5。
8.3中还有一个比较取反,对分频有一定影响。
c. 比较匹配OCR0设在TCNT0初值跟0xFF的之间的值即可,占空比不一定。 d. 例8.1和8.2中输出的波形占空比都是50%,但是例8.3中输出波形的占空比不是50%,
像此例中占空比是60%。 e. 可以,调整OCR0的值即可。
2. 比较使用定时器和不用定时器进行LED动态扫描有何不同。讨论采用软件延时和采用中
断这两种不同的方式进行数码管扫描的优缺点。在程序设计时应该采用哪种?
a. 使用定时器的动态扫描是直接利用系统自身的时钟信号进行定时,而不使用定时器的
中断扫描需要使用外部时钟信号来实现定时,后者系统复杂一点。
b. 采用软件延时缺点是不准确,优点是简单。采用中断优点是定时时间会准确,缺点是
相对复杂。
c. 程序设计中应该采用系统内部时钟,加上定时器来产生定时信号。
3. 当定时计数器工作在普通模式和CTC模式时,都可以产生一个固定的定时中断。如果要
求精确的定时中断,采用那种模式比较好?为什么?
采用CTC模式比较好,不需要在中断服务程序中重新对TCNT0进行初始化。
4. 如果采用PWM输出频率可调的正弦波,或者幅度可调的正弦波,实现的思想方法是什么?
软件应该如何设计?
输出频率可调的正弦波,可以通过修改TCNT0的初始值,幅度可调的正弦波则可以通过 修改OCR0的值来实现。软件设计也就是在中断服务程序中不断修改这些值。
5. 请思考采用定时器测量频率的方法,并讨论和给出你设计方法的频率测量精度和频率测
量范围。
在一只限定的时间内,对测量信号输入的个数计数,适用高频。例如限定时间为100ms,
则频率测量误差为正负10Hz.由于T/C0长度为8位,则测量范围为255Hz.
6. 请思考采用定时器测量周期的方法,并讨论和给出你设计方法的周期测量精度和周期测
量范围。
在一只限定脉冲个数之间的时间间隔,再转化为测量信号的频率,使用低频。例如限
定脉冲个数为N个,则在不考虑中断响应时间情况下,周期测量误差为正负(2微秒/N),否则为正负(2-5微秒/N).