最近看到很多网友都想知道单片机怎样产生正弦波,这里我收集了一些单片机产生正弦波的文章,如果你想搞一个模拟采集系统,那末先用单片机产生一个正弦波来调通数据传输通道。然后,再控制AD采集实际
波形将其转换为数字信号送到已调整好的传输通道中。
======================================================
//Title: Project0502 m8-USB 正弦波发生程序
//Version: 05.02
//Last updata: 2007.05.2
//Reffer: m8receive5
//Target: ATmega8L(2.7~5.5V)
//EEPROM: No use
//circuit: CP2102.ddb
//Frequency: 内部8MHz
// 单片机的内部震荡频率可通过下载软件PonyProg2000改动
//点击小锁图标后,特别小心Write和Read钮千万别按错!假若你在
//所有熔丝位=1时,按动了Write 单片机便被锁死,恢复起来特别麻烦
//只能更换mega8芯片了。
//正确的方法是先按Read,按照下面的提示修改后,再Write
// Flash fuse bits:Calibrated Internal RC Oscillator
// CKSEL3..0 0100 ~ 0001(0=\/)
// 0001=1M,0010=2M,0011=4M,0100=8MHz
//串口发送 38400baud
////////////////////////////////////////////////////////
#include <iom8v.h>
#include <macros.h>
#include <math.h>
unsigned char Flag;
unsigned char sBUF[3]={0xff,0x00,0xff}; //串口发送缓存
void uart_init(void);
void send(unsigned char sd );
void delay(unsigned int n);
#pragma interrupt_handler t1_interrupt:9
/**********************************************/
void main()
{
unsigned int m;
unsigned int mmax;
unsigned int sinData;
unsigned char DataR1; //sin 第一个字节
unsigned char DataR2; //sin 第二个字节
float x;
float sin(float n);
SP=0x025F; //栈针设置
/*setting watchdog */
//编程熔丝位WDTON
WDTCR=(1<<WDCE)|(1<<WDE); //Turn off WDT
WDTCR=0x0f; //enable watchdog,2S
/*setting I/O port*/
//PD2-按钮
//PD3-发光管LD2
DDRD=0x08;
_CLI();
/*setting timer1 */
TIMSK=(1<<TOIE1); //允许T/C1溢出中断
TCCR1B=0x00; //停止定时器1
TCNT1H=0xfe; //设置定时器初值
TCNT1L=0x0b;
TCCR1A=0x00;
TCCR1B=0x02; //启动定时器1,分频因子fp为8
//T1装载DH的计算值为 T1=(1/fosc)*fp*(ffff-DH)
//T1装载DH的计算值为 T1=1/8K000*fp*[(ffff-DH)=7D0] =2mS(F82F)
/**运行前初始化**/
uart_init(); //串口初始化
delay(60000);
PORTD |=0x08; //LD2-on
Flag=0x00;
m=0;
////////////////////////////////////////////////////////////////////
//下为主循环,循环周期2mS,相当于500sps的采样率
//2006.10.5 为简化处理,本地串口发送的数据格式如下
//软件产生;频率10Hz,精度为10bits的正弦波
//待传输的字节数为3Bytes,其格式如下:
// 字节0: 1,x,x,x xxxx
// 字节1:0,x,x,x x,x,D9,D8
// 字节2: D7,D6,D5,D4,D3,D2,D1,D0
//字节0的最高位永远是1,字节1的最高位永远是0,字节2不定
//这样,上传的数据串的字头为 01x 01x 01x 01x.....接收侧用程序
//便可以很容易排出正确的接收顺序。
//25--20Hz
////////////////////////////////////////////////////////////////////
_SEI(); //开全局中断,2mS定时器中断
mmax=50; //mmax决定频率,2mS*mmax=1000/f
while(1)
{
_WDR();
while(!(Flag&0x01)); //waitting 2mS
Flag=0x00;
if(m>mmax) //控制波形的频率
{
PORTD ^=0x08;
m=0;
x=0;
}
x=m*2*3.1416/mmax;
sinData=500*sin(x)+500;
DataR2=sinData; //低8位送DataR2
DataR1=sinData>>8; //高2位送DataR1
sBUF[0]=0x80;
sBUF[1]=DataR1&0x7f; //保证最高位=0;
sBUF[2]=DataR2;
send(sBUF[0]); //串口发送3Bytes数据
send(sBUF[1]);
send(sBUF[2]);
m++;
}
}
/***************************************************/
void uart_init(void)
{
UCSRA=(1<<U2X);
UCSRB=(1<<RXCIE)|(1<<RXEN)|(1<<TXEN)|(0<<UCSZ2);
UCSRC=0x86 ; //1000 0110 UPM1/UPM0=00,无校验
UBRR=25; //8M-38400baud/25/U2x=1,error=0.2%
}
void send(unsigned char sd ) //查询方式串口发送
{
UDR=sd;
while(!(UCSRA&0x40)); //等待发送完毕
UCSRA|=0x40;
}
void t1_interrupt(void)
{
TCNT1H=0xf8; //重装定时器1值 2mS
TCNT1L=0x90; //2mS-f890(f82f-8M/8计算值)
Flag |=0x01; //中断标记
//PORTD ^=0x08; //LD2 测试脚
}
void delay(unsigned int n)
{
unsigned int u;
for (u=1; u<n; u++){}
}
======================================================
本程序用我已有的电脑显示程序调通