📄 tc1_6.c
字号:
/*****************************************************
**** AVR T/C1 使用范例6(PWM输出实现正弦波输出) ****
**** 作者: liugangdi ****
**** 编译器:WINAVR20050214 ****
**** 日期:2005.11.26 ****
******************************************************/
/*说明: 用PWM方式来产生一个1KHz左右的正弦波,幅度为0-Vcc/2。
关于用PWM输出实现正弦波输出是AVR单片机的PWM输出一个重要
应用。原理即:通过按照正弦波规律改变占空比来实现正弦波的
发生。正弦表事先计算好存在EEPROM或者FLASH区域。程序根据这
个表决定占空比。而正弦表的计算可以根据一个固定的公式
f(x) = 64 + 63 * sin(2πx/180) x∈[0…127] 。
如果在一个正弦波周期中采用128个样点,那么对应1KHz的正弦
波PWM的频率为128KHz。实际上,按照采样频率至少为信号频率
的2倍的取样定理来计算,PWM的频率的理论值为2KHz即可。考虑
尽量提高PWM的输出精度,实际设计使用PWM的频率为16KHz,即一
个正弦波周期(1KHz)中输出16个正弦波样本值。这意味着在128
点的正弦波样本表中,每隔8点取出一点作为PWM的输出。
每次计数器溢出中断的服务中取出一个正弦波的样点值到比较匹配寄
存器中,用于调整下一个PWM的脉冲宽度,这样在PD4、PD5引脚上输出
了按正弦波调制的PWM方波。当PD4、PD5的输出通过一个低通
滤波器后,便得到一个1KHz的正弦波了。用T/C1,选择工作模式10,
设置ICR1=250为计数器的上限值。
这个功能可以实际应用于产生双音多频信号(DTMF)等。*/
//仿真说明:用proteus软件仿真时,图形是正弦波。可能是滤波器设计的不是很好,
//有毛刺现象。
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdio.h>
//#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>
#include <string.h>
#define PD5 5
#define PD4 4
#define OCRA OCR1A //OCR=OCR1A
#define OCRB OCR1B //OCRB=OCR1B
unsigned char i_a=0,i_b=0;
unsigned char I_A=8,I_B=8;
unsigned char ocr_rega[2],ocr_regb[2];
unsigned char auc_SinParam[128] = {
64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,118,120,121,
123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,124,123,121,120,118,
117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,79,76,73,70,67,64,60,57,54,51,48,
45,42,39,36,33,31,28,25,23,21,18,16,14,12,10,9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,
7,9,10,12,14,16,18,21,23,25,28,31,33,36,39,42,45,48,51,54,57,60};
//unsigned char sin_table[128] ;
//初始化计数器
void init(void)
{
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);//升序记数时比较匹配将清零OC1A/OC1B,降序记数时比较匹配将置位OC1A/OC1B
TCCR1B|=(1<<WGM13)|(1<<CS10); //10模式,相位修正的PWM模式,TOP值由ICR1决定,时钟不分频
ICR1=250; //置TOP值
DDRD|=(1<<PD5)|(1<<PD4); //PD4、PD5设为输出
TIMSK|=(1<<OCIE1A)|(1<<OCIE1B); //允许计数器比较匹配A、B中断
}
//输出比较A中断服务程序
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
i_a+=I_A; //每隔8个取一个数,新样点指针
if (i_a>127)i_a-=128; //样点指针调整
memcpy (ocr_rega,auc_SinParam+i_a,1); //从EEPROM中取出正弦数据
OCRA=ocr_rega[0]; //更新OCR1A
}
//输出比较B中断服务程序
SIGNAL(SIG_OUTPUT_COMPARE1B)
{
i_b+=I_B; //每隔8个取一个数,新样点指针
if (i_b>127)i_b-=128; //样点指针调整
memcpy(ocr_regb,auc_SinParam+i_b,1); //从EEPROM中取出正弦数据
OCRB=ocr_regb[0]; //更新OCR1B
}
//主程序,主要是初始化和进入休眠模式。因为利用AVR的PWM输出实现波形产生,不占用CPU的计算资源,CPU
//可以工作于休眠模式,有助于实现低功耗的设计
int main(void)
{
//eeprom_read_block(buf, sin_table, 128); //
init(); //调用初始化
sei(); //开总中断
set_sleep_mode(SLEEP_MODE_IDLE); //设置休眠模式为空闲模式
while(1)
{
sleep_mode(); //进入休眠状态
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -