AVR单片机ATMEGA48的EEPROM操作例子/***************************************************** CodeWizardAVR Panxiaoyi快速PWM,也可以叫单斜率PWM*****************************************************/#include <mega48.h>unsigned char eeprom i=0; //把变量放保存在EEPROM上/赋值与否并不影响i的值void main(void){TCCR0A=0b10000011; //比较匹配时OC0A=0,计数到比较值时OC0A=1,TOP固定等于255TCCR0B=0b00000001; //时钟=1分频DDRD.6=1; //PD6必须设置为输出时OC0A 输出的PWM才有效DDRD.2=0;PORTD.2=1; //PD2接按键输入/上拉电阻使能while(1){if(PIND.2==0) //如果按键按下/简单的按键防抖动{while(PIND.2==0); //等待按键松开i+=10; //更新EEPROM的数据i/重新来电后数据不变}OCR0A = i ; //刷新比较值,PWM占空比随之改变}}ATMEGA48的USART串口与PC通讯例子/***************************************************** CodeWizardAVRChip type : ATmega48VClock frequency : 7.372800 MHzMemory model : SmallExternal SRAM size : 0Data Stack size : 128波特率9600/8个数据位 /1个停止位 /无校验M8V20实验板硬件设置1: J5的2个跳线帽短接,使用外部晶振7.3728MHz2: J6与J7的4个跳线帽短接,使用MAX232,其他跳线开路3: DB9接口连接到电脑请配合串口调试软件SSCOM32或者comdebug进行调试*/#include <mega48.h>#include <stdio.h>#include <delay.h>void main(void){UCSR0B=0x18; //下面是3条语句是串口初始化语句UCSR0C=0x06;UBRR0L=0x2F;while(1) //循环{unsigned char data; //定义一个局部变量data=getchar(); //等待,直到接收到一个数据putchar(data); //将接收到的数据发送出去}} //endATMEGA48的T/C2与精确时钟例子/*****************************************************CodeWizardAVR V1.25.6 ProfessionalChip type : ATmega48Clock frequency : 7.372800 MHzMemory model : SmallExternal SRAM size : 0Data Stack size : 128计算: 1秒= 时钟/ ( 分频* 计数)假设时钟= 7372800 Hz 那么: 1秒= 7372800 / ( 分频* 计数)得: 计数=7372800/分频由于分频只有1/8/32/64/128/256/1024 供我们选择,而计数最高只有8位(255)为了不占用资源,中断次数尽量少一点比较好,并且中断时间越短越好所以我们可以选择计数= 时钟7372800 / 分频1024 / 30次中断= 240这个240就是T/C2的计数上限TOP*****************************************************/#include <mega48.h>unsigned char TC2A=0;interrupt [TIM2_COMPA] void timer2_compa_isr(void){TC2A++;if(TC2A>=30) TC2A=0;if(TC2A>25) PORTD.3=1; else PORTD.3=0;}void main(void){TCCR2A|=2; //工作于CTC模式(比较匹配时计算器清零)OCR2A=240; //设置TOP的值(计算器的上限值)TCCR2B|=7; //取系统时钟1024分频作为T/C2时钟TIMSK2=2; //使能计数器的值达到TOP 时产生中断DDRD.3=1; //使用PD3每秒驱动蜂鸣器"嘀"一次#asm("sei") //插入汇编语句,打开全局中断while (1){#asm("nop") //空操作的汇编代码,等待中断发生};}/****************************************************假设程序还有一个3位数码管动态扫描任务,这时我们就可以这样计算1:数码管的扫描频率在75-85Hz比较合适,太低会闪烁,太高占用资源2:每扫描一次就必须分3次显示,分别是个位/十位/百位3:这时我们可以计数出显示频率是225-255Hz(中断频率),在这里假设=240Hz 4:这时我们就可以顺便使用这个T/C2定数中断来保证扫描的可靠运行了5:计算: 计数= 时钟7372800 / 分频128 / 240次中断= 240 ***/ATMEGA48外部电平变化中断PCINT例子/***************************************************** CodeWizardAVRChip type : ATmega48VClock frequency : 1.000000 MHzMemory model : SmallExternal SRAM size : 0Data Stack size : 128外部PCINT0-PCINT7共享一个中断源PCINT0外部PCINT8-PCINT14共享一个中断源PCINT1外部PCINT16-PCINT23共享一个中断源PCINT2没有使用延时/通信语句,所以使用内部/外部时钟都可以每按动INT0按键一次,PD3的电平就翻转一次本例子没有考虑太多的按键防抖动功能*******************/#include <mega48.h>//外部PCINT16-PCINT23共享一个中断源PCINT2//请参考M48数据手册的48页/75页interrupt [PCINT2] void PCINT2_isr(void){PORTB.0=~PORTB.0; //电平取反PCIFR|=4; //清除PCINT2中断触发标记,防止按键抖动}void main(void){PORTD=255;DDRD=0; //设置PCINT16-PCINT23端口为输入,上拉电阻有效PORTB.0=0;DDRB.0 =1; //设置PB0输出低电平,准备驱动蜂鸣器PCICR|=4; //使能PCINT16-PCINT23外部电平变化中断PCMSK2|=4; //使能PCINT18有效#asm("sei") //插入汇编语句,打开全局中断while (1) //循环,等待中断{#asm("nop") //空操作的汇编代码,等待中断发生};}ATMEGA48外部中断INT0例子/***************************************************** CodeWizardAVRChip type : ATmega48VClock frequency : 1.000000 MHzMemory model : SmallExternal SRAM size : 0Data Stack size : 128INT0最好接一个4.7K的上拉电阻,按键对地有效没有使用延时/通信语句,所以使用内部/外部时钟都可以每按动INT0按键一次,PD3的电平就翻转一次本例子没有考虑太多的按键防抖动功能*******************/#include <mega48.h>interrupt [2] void INT0_isr(void) //INT0的中断向量是2,请参考M48数据手册的48页{PORTD.3=~PORTD.3; //电平取反EIFR|=1; //清除INT0中断触发标记,防止按键抖动}void main(void){PORTD.2=1;DDRD.2=0; //设置INT0端口为输入,上拉电阻有效PORTD.3=0;DDRD.3 =1; //设置PD3输出低电平,准备驱动蜂鸣器EIMSK|=1; //打开INT0中断EICRA|=3; //INT0上升沿触发#asm("sei") //插入汇编语句,打开全局中断while (1) //循环,等待中断{#asm("nop") //空操作的汇编代码,等待中断发生};}ATMEGA48的ADC模数转换例子////ADC结果由串口输出到电脑显示#include <mega48.h>#include <stdio.h>#include <delay.h>void main(void){//外部时钟 7.3728MHz (请取消时钟8分频)//串口初始化,波特率9600Hz,8个数据位,1个停止位,无奇偶校验,无中断使能UCSR0B=8;UCSR0C=6;UBRR0L=47;//**************************************************************** *ADMUX=96; //设置参考电压为AVCC,结构左对齐(就是8位精度)ADCSRA|=135; //使能ADC,ADC时钟=系统时钟128分频while (1){unsigned char adc;ADMUX=ADMUX&240|2; //清除已选择的ADC通道,选择新的ADC通道(0-7)ADCSRA|=64; //启动单次ADC转换while((ADCSRA&16)==0); //等待ADC转换结束adc=ADCH; //结果左对齐只需读取高8位数据ADCSRA|=16; //清除ADC转换结束标记putchar(adc/100+48); //从串口输出ADC的百位数putchar(adc/10%10+48); //从串口输出ADC的十位数putchar(adc%10+48); //从串口输出ADC的个位数delay_ms(500); //延时putchar(13); //回车putchar(10); //换行}}ATMEGA8/ATMEGA16多机通讯例子下面是一个M16的多机通讯例子,也适合M8,只需要修改头文件就可以了,本例子在3台机上测试并稳定通过主机代码/* AVR单片机DIY网潘小艺 CVAVR1.25.9通讯规则:01:时钟7.3728 MHz/波特率9600/9个数据位/奇校验/1个停止位/硬件多机通讯功能/02:通讯连接采用硬件MAX485,双向单工03:MAX485的RE/DE并联接到单片机的PD2脚(高电平发送/低电平接收)04:所有MAX485的A脚并联/B脚并联/D脚接TXD/R脚接RXD05:每个上行/下行的数据包的字节个数都是一样的(通讯数据量)06:数据包格式: 地址_数据1_数据2_数据3_数据n_CRC8校验码07:所有单元的数据接收都是采用中断+查询的方式08:总是由主机向从机下发一个数据包,从机收到数据包并校验正确后向主机回复一个数据包09:不管是主机还是从机,如果收到的数据包有任何错误,都将丢弃该数据包,等效于没有接收10:通讯采用主机轮询方式,从机之间不能相互通讯,必须通过主机才能交换数据11:无效地址是0,主机地址是1,从机地址是11.12.13...广播地址是255 */#include <mega16.h>#include <delay.h>#include <usart.h>#include <crc8.h>#define amount 10//设定通讯数据量#define address1//请在这里设定本机地址#define max485_out PORTD.2=1#define max485_in PORTD.2=0#define max485_RW_ok DDRD.2=1unsignedchar send[amount];//发件箱unsigned charinbox[amount];//收件箱unsigned charn=0;//记忆接收中断的次数unsigned char x=0;//******************************************************************* *******************void usart_out(unsigned char *datas,unsigned char n){unsigned char i=0;max485_out;//使MAX485处于发送状态while(i<n)//一共发送n个数据{if(i==0) UCSRB|=1; else UCSRB&=254;UDR=*(datas+i);//装载数据开始发送while((UCSRA&64)==0);//等待发送结束UCSRA|=64;//清除发送结束标志i++;//发送次数统计}max485_in;//使MAX485处于接收状态}//******************************************************************* *******************interrupt[12]Rxd_isr(void)//接收中断{if( UCSRA&28 ){ n=UDR; n=0; UCSRA|=0x01; } else //接收出错就重新打开地址帧筛选功能{if( UCSRB&2 )n=0;//检测到地址信息时计数清零inbox[n]=UDR; n++;//把接收到的数据保存到收件箱if( inbox[0]==address ) UCSRA&=254; else UCSRA|=0x01; //地址筛选}}//******************************************************************* *******************void main(void){usart_init();max485_in;max485_RW_ok;DDRA=7;//通讯状态指示#asm("sei");while(1){x=~x;//测试用的变量PORTA.0=~PORTA.0;//观察单片机是否死机(供电一定要好)//************************************与从机11对话****************************************if(x) send[3]=0; elsesend[3]=255; //更新发件箱的数据(测试代码)send[0]=11;//指向从机地址send[amount-1]=crc8(send,amount-1);//计算发件箱数据的crc8校验码usart_out(send,amount);//将发件箱的数据send[]发送出去;n=0;//计数复位,准备接收新数据 delay_ms(15);//等待从机回复数据,这个时间要计算好if(n==amount && inbox[amount-1]==crc8(inbox,amount-1)) //接收正确处理与测试{PORTA.1=1; delay_ms(10); PORTA.1=0;}else//接收错误处理与测试 {PORTA.2=1; delay_ms(10); PORTA.2=0;}//************************************与从机12对话****************************************if(x) send[3]=50; elsesend[3]=200; //更新发件箱的数据(测试代码)send[0]=12;//指向从机地址send[amount-1]=crc8(send,amount-1);//计算发件箱数据的crc8校验码usart_out(send,amount);//将发件箱的数据send[]发送出去;n=0;//计数复位,准备接收新数据 delay_ms(15);//等待从机回复数据,这个时间要计算好if(n==amount && inbox[amount-1]==crc8(inbox,amount-1)) //接收正确处理与测试{PORTA.1=1; delay_ms(10); PORTA.1=0;}else//接收错误处理与测试 {PORTA.2=1; delay_ms(10); PORTA.2=0;}}} //end从机(需要增加多个从机时可以修改从机的地址就可以了)//从机11#include <mega16.h>#include <usart.h>#include <crc8.h>#define amount 10//设定通讯数据量#define address11//请在这里设定本机地址#define max485_out PORTD.2=1#define max485_in PORTD.2=0#define max485_RW_ok DDRD.2=1unsignedchar send[amount];//发件箱unsigned charinbox[amount];//收件箱unsigned charn=0;//记忆中断次数//******************************************************************* *******************void usart_out(unsigned char *datas,unsigned char n){unsigned char i=0;max485_out;//使MAX485处于发送状态while(i<n)//一共发送n个数据{if(i==0) UCSRB|=1; else UCSRB&=254;UDR=*(datas+i);//装载数据开始发送while((UCSRA&64)==0);//等待发送结束UCSRA|=64;//清除发送结束标志i++;//发送次数统计}max485_in;//使MAX485处于接收状态}//******************************************************************* *******************interrupt[12]Rxd_isr(void)//接收中断{if( UCSRA&28 ){ n=UDR; n=0; UCSRA|=0x01; } else //接收出错就重新打开地址帧筛选功能{if( UCSRB&2 )n=0;//检测到地址信息时计数清零inbox[n]=UDR; n++;//把接收到的数据保存到收件箱if( inbox[0]==address ) UCSRA&=254; else UCSRA|=0x01; //地址筛选if( n==amount )//如果接收到完整的数据包{if( inbox[amount-1]==crc8(inbox,amount-1) )//如果crc8校验正确就...{send[0]=1;//发件箱地址指向主机//send[1]=?//请更新发件箱的数据//send[n]=?send[amount-1]=crc8(send,amount-1);//产生发件箱的crc8校验码usart_out(send,amount);//发送发件箱的数据包/查询方式比较耗时OCR1A=inbox[3];//收件箱测试(控制T/C1的PWM驱动LED)}}}}//******************************************************************* *******************void main(void){usart_init();max485_in;max485_RW_ok;TCCR1A =0B10000001;//OCR1A/PD5/8位快速PWMTCCR1B =0B00001001;//时钟1分频DDRD |=0b00100000;//输出使能OCR1A =255;//初始化PWM输出100%占空比#asm("sei")while (1){};}USART.h文件内容//波特率9600/9个数据位/1个停止位/奇校验/收发开启/接收中断/地址过滤void usart_init(void){UCSRA=0x01;UCSRB=0x9C;UCSRC=0xB6;UBRRH=0x00;UBRRL=47;}CRC8.h文件内容unsigned char crc8(unsigned char *ptr, unsigned char len){unsigned char i;unsigned char crc=0;while(len--!=0){for(i=1; i!=0; i*=2){if((crc&1)!=0) {crc/=2; crc^=0x8C;}else crc/=2;if((*ptr&i)!=0) crc^=0x8C;}ptr++;}return(crc);}ATMEGA48多机通讯例子主机程序********************************************************************* ********************************/* AVR单片机DIY网潘小艺 CVAVR1.24.8d通讯规则:1:时钟7.3728 MHz/波特率9600/9个数据位/奇校验/1个停止位/硬件多机通讯功能/2:通讯连接采用硬件MAX485,双向单工3:每个上行/下行的数据包的字节个数都是一样的(通讯数据量)4:每个上行/下行的数据包都采用CRC8校验5:数据接收采用中断+查询的方式6:总是由主机向从机发送一个数据包,从机收到数据包后向主机回复一个数据包7:不管是主机还是从机,如果收到的数据包有任何错误,都将丢弃该数据包,等效于没有接收8:从机之间不能相互通讯,必须通过主机才能交换数据9:无效地址是0,主机地址是1,从机地址是2.3.4......广播地址是255*/#include <mega48.h>#include <delay.h>#define amount 10 //设定通讯数据量(包括1个地址帧,n个数据帧,1个校验帧)#include <usart.h>#include <1wire.h> //CRC校验函数就在这个文件里面unsigned char send[amount]; //发件箱unsigned char inbox[amount]; //收件箱unsigned char n=0; //记忆中断次数//--------------------------------------------------------------------interrupt[19] Rxd_isr(void) //接收中断{unsigned char ERROR=0;if( UCSR0A&4 || UCSR0A&16 ) ERROR=1; //奇偶效验错误或者帧错误就记录下来inbox[n]=UDR0; //保存到收件箱n++;//记忆中断次数if(ERROR) inbox[0]=0; //如果通讯有错,收件箱的地址帧就标记成无效地址0}//---------------------------------------------------------------------void main(void){USARTinit(); //串口初始化UCSR0A=0; //主机关闭地址筛选功能(多机通讯功能)#asm("sei") //打开全局中断while(1){//-------------与从机2对话,与其他从机对话与下面的程序类似-------------------n=0;//中断次数清0inbox[0]=0; //收件箱地址清0send[0]=2; //改变这个地址就可以实现与某个从机对话send[amount-1]=w1_dow_crc8(send,amount-1); //计算发件箱的crc8校验码TXD(send); //将发件箱的数据send[]发送出去;//等待,从机接收到数据后会回复数据的,如果是10个字节数据量,不能少于13ms//这个时间由人工计算,要考虑从机由于各种中断延长回复时间的可能 delay_ms(30);//如果收件箱已经收到amount个数据,并且crc8校验成功就...if(n==amount && inbox[amount-1]==w1_dow_crc8(inbox,amount-1)) {if(inbox[0]==1) //如果收件箱地址帧属于本机就运行下面的测试代码{DDRD.3=1;PORTD.3=1; delay_ms(50);PORTD.3=0; delay_ms(950);}if(inbox[0]==255){//请在这里添加收到广播数据的处理程序}}}} //end//******************************************************************* *******************************从机程序//******************************************************************* *******************************#include <mega48.h>#include <delay.h>#define amount 10 //设定通讯数据量(包括1个地址帧,n个数据帧,1个校验帧)#include <usart.h>#include <1wire.h>#define address 2 //请在这里设定本机地址unsigned char send[amount]; //发件箱unsigned char inbox[amount]; //收件箱unsigned char n=0; //记忆中断次数//--------------------------------------------------------------------interrupt[19] Rxd_isr(void) //接收中断{unsigned char ERROR=0;if( UCSR0A&4 || UCSR0A&16 ) ERROR=1; //记录奇偶效验错误或者帧错误inbox[n]=UDR0;//把接收到的数据保存到收件箱n++;//记忆接收的次数if(ERROR)//如果通讯有错....{n=0;//接收计数清0inbox[0]=0;//把地址改为无效地址0UCSR0A|=0x01;//重新打开接收器的地址帧筛选功能}//如果地址匹配本机或者是广播地址就关闭地址筛选(多机通讯)功能if(inbox[0]==address ||inbox[0]==255) UCSR0A&=254;if(n==amount)//接收到amount个数据以后...{n=0;//接收计数清0UCSR0A|=0x01;//重新打开接收器的地址帧筛选功能if(inbox[amount-1]==w1_dow_crc8(inbox,amount-1)) //如果crc8校验正确就...{if(inbox[0]==address) //如果地址匹配本机就回复数据{send[0]=1;//发件箱地址指向主机send[amount-1]=w1_dow_crc8(send,amount-1); //产生发件箱的crc8校验码TXD(send);//发送发件箱的数据包send[]//请在这里备份你的收件箱信息}if(inbox[0]==255) //如果是广播地址就...{//请在这里添加你的代码//收到广播数据请不要回复}}}}//---------------------------------------------------------------------void main(void){USARTinit();//串口初始化UCSR0A=0x01;//从机打开地址帧筛选功能(多机通讯模式)#asm("sei")//打开全局中断while(1){//请在这里添加你的代码}} //end//******************************************************************* **************************<usart.h> 头文件//******************************************************************* **************************//波特率9600/9个数据位/1个停止位/奇校验/收发开启/接收中断void USARTinit(void){UCSR0B=0x9C;UCSR0C=0x36;UBRR0L=0x2F;PORTD.4=0; //M AX485平时工作在接收状态DDRD.4=1;}//-----------------------------------------------------------//从数组datas[]的首地址开始发送amount个数据,其中第0个数据是地址帧,其他是数据帧void TXD(unsigned char *datas){unsigned char i=0;PORTD.4=1; //使MAX485处于发送状态while(i<amount) //一共发送amount个数据{if(i==0) UCSR0B|=1; else UCSR0B&=254;UDR0=*(datas+i); //装载数据开始发送while((UCSR0A&64)==0); //等待发送结束UCSR0A|=64; //清除发送结束标志i++;//发送次数统计}PORTD.4=0; //使MAX485处于接收状态}//******************************************************************* **************************ATMEGA48中T/C0的相位修正PWM与快速PWM例子/***************************************************** CodeWizardAVR V1.25.3 Professional相位修正PWM,也可以叫双斜率PWM*****************************************************/。