AVR_C语言编程通用脚本
- 格式:doc
- 大小:22.50 KB
- 文档页数:2
A VR单片机程序* 文件名:闪烁灯.c* 杜邦线接法:用单条杜邦线把PD.0与J38的1端相连接。
***********************************************************************/ #include <avr/io.h>#define F_CPU 8000000 //这里的值是单片机工作的有关晶振频率#include <util/delay.h>#define LED1 PORTD|=~0XFE //LED=1 LED不亮#define LED0 PORTD&=0XFE //LED=0 LED发光int main(void){DDRD = 0x01; //PD0定义为输出,PD的其他端口为输入。
while(1){LED1;_delay_ms(500);LED0;_delay_ms(500);}}/********************************************************************* 文件名:闪烁灯2.c* 创建人:东流,2012年2月10日* 版本号:1.0* 杜邦线接法:用8针杜邦线把PD与J38的1--8连接(PD0对应J38的1端)。
用杜邦线把PB0对应J38的9端。
用杜邦线把PB1对应J38的10端。
用杜邦线把PB2对应J38的11端。
用杜邦线把PB3对应J38的12端。
***********************************************************************/ #include <avr/io.h>#define F_CPU 8000000 //这里的值是单片机工作的有关晶振频率#include <util/delay.h>int main(void){DDRD = 0xff;DDRB = 0x0f;while(1){/*北面的三个LED亮*/PORTD = 0xf8;PORTB = 0xff;_delay_ms(300);/*东面的三个LED亮*/PORTD = 0xc7;PORTB = 0xff;_delay_ms(300);/*南面的三个LED亮*/PORTD = 0x3f;PORTB = 0xfe;_delay_ms(300);/*西面的三个LED亮*/PORTD = 0xff;PORTB = 0xf1;_delay_ms(300);/*北面的两个LED亮,中间一个不亮*/ PORTD = 0xfa;PORTB = 0xff;_delay_ms(300);/*东面的两个LED亮,中间一个不亮*/ PORTD = 0xd7;PORTB = 0xff;_delay_ms(300);/*南面的两个LED亮,中间一个不亮*/ PORTD = 0xbf;PORTB = 0xfe;_delay_ms(300);/*西面的两个LED亮,中间一个不亮*/ PORTD = 0xff;PORTB = 0xf5;_delay_ms(300);/*12个LED全亮*/PORTD = 0x00;PORTB = 0xf0;_delay_ms(200);/*12个LED全灭*/PORTD = 0xff;PORTB = 0xff;_delay_ms(200);/*12个LED全亮*/PORTD = 0x00;PORTB = 0xf0;_delay_ms(200);/*12个LED全灭*/PORTD = 0xff;PORTB = 0xff;_delay_ms(200);_delay_ms(500); //延时0.5秒}}/********************************************************************* 文件名:闪烁灯2.c* 描述: 在LED上根据要求,进行不一致的显示。
//lcd1602.h//杨清云 2012-12-29#include <iom16v.h>#include <macros.h>// LCD Driver ST70006-OE//-----------------------------------------------#define uchar unsigned char#define uint unsigned int#define LCM_RS_1 PORTD|=BIT(PD4)#define LCM_RS_0 PORTD&=~BIT(PD4)#define LCM_RW_1 PORTD|=BIT(PD5)#define LCM_RW_0 PORTD&=~BIT(PD5)#define LCM_EN_1 PORTD|=BIT(PD6)#define LCM_EN_0 PORTD&=~BIT(PD6)//======================================#define DataPort PORTB#define Busy 0x80#define xtal 8const uchar str[]={"The Voltage Is:"};//========函数声明=========void Delay_1ms(void);void Delay_nms(uint n);void WaitForEnable(void);void LcdWriteData(uchar W);void LcdWriteCmd(uchar CMD);void DisplayOneChar(uchar Cmd, uchar wData);void DisplayValue(unsigned int Value);/*-------------名称:void DisplayOneChar(uchar Cmd, uchar wData)?参数:uchar Cmd,uchar wData输出:无-------------------*/void DisplayOneChar(uchar Cmd, uchar wData){LcdWriteCmd(Cmd);LcdWriteData(wData);}/*-------------名称:void DisplayValue(unsigned int Value)参数:unsigned int Value输出:无-------------------*/void DisplayValue(unsigned int Value){uchar Val[4];uchar i=0;Val[3]=(uchar)(Value/1000);//将数据转换为BCD码的千位Val[3]=Val[3]+0x30;//将BCD码转换为ASCII码Val[2]=(uchar)(Value%1000/100);//将数据转换为BCD码的百位Val[2]=Val[2]+0x30;//将BCD码转换为ASCII码Val[1]=(uchar)(Value%1000%100/10);//将数据转换为BCD码的十位 Val[1]=Val[1]+0x30;//将BCD码转换为ASCII码Val[0]=(uchar)(Value%1000%100%10);//将数据转换为BCD码的个位 Val[0]=Val[0]+0x30;//将BCD码转换为ASCII码LcdWriteCmd(0x80);for(i=0;i<15;i++){LcdWriteData(str[i]);//显示字符串}DisplayOneChar(0xCb,'V');//显示电压单位VDisplayOneChar(0xCA,Val[0]);//显示千分位DisplayOneChar(0xC9,Val[1]);//显示百分位DisplayOneChar(0xC8,Val[2]);//显示十分位DisplayOneChar(0xC7,'.');//显示小数点DisplayOneChar(0xC6,Val[3]);//显示整数}//**************LCD初始化***************************/*-------------名称:void InitLcd(void)参数:无输出:无-------------------*/void InitLcd(void){DDRB=0xff;PORTB=0x00;DDRD=0xff;// DDRD|=LCD_RS_1|LCD_RW_1|LCD_EN_1;PORTD=0x00; //PORTD&=~LCD_RS_0|LCD_RW_0|LCD_EN_0;LcdWriteCmd(0x38);Delay_nms(5);LcdWriteCmd(0x38);Delay_nms(5);LcdWriteCmd(0x38);Delay_nms(5);LcdWriteCmd(0x38);LcdWriteCmd(0x08);LcdWriteCmd(0x01);LcdWriteCmd(0x06);LcdWriteCmd(0x0c);}//************写命令到LCD**************/*-------------名称:void LcdWriteCmd(uchar CMD)参数:CMD输出:无-------------------*/void LcdWriteCmd(uchar CMD){WaitForEnable();LCM_RS_0;LCM_RW_0;_NOP();DataPort=CMD;_NOP();LCM_EN_1;_NOP();_NOP();LCM_EN_0;}//*************写数据到LCD***************/*-------------名称:void LcdWriteData(uchar dataW)参数:dataW输出:无-------------------*/void LcdWriteData(uchar dataW){WaitForEnable();LCM_RS_1;LCM_RW_0;_NOP();DataPort=dataW;_NOP();LCM_EN_1;_NOP();_NOP();LCM_EN_0;}//*******************检测LCD忙信号子函数********************* /*-------------名称:void WaitForEnable(void)参数:无输出:无-------------------*/void WaitForEnable(void){uchar val;DataPort=0xff;LCM_RS_0;LCM_RW_1;_NOP();LCM_EN_1;_NOP();_NOP();DDRB=0x00;val=PINB;while(val&Busy)val=PINB;LCM_EN_0;DDRB=0xff;}/*-------------名称:void Delay_1ms(void)参数:无输出:无-------------------*/void Delay_1ms(void)//1mS延时子函数{ uint i;for(i=1;i<(uint)(xtal*143-2);i++);}/*-------------名称:void Delay_nms(void)参数:无输出:无-------------------*/void Delay_nms(uint n)//n*1mS延时子函数{uint i=0;while(i<n){Delay_1ms();i++;}}。
/*ATMEL的DATAFLASH操作函数库(FOR AT45DB161D)*/#include <avr/io.h>#include <util/delay.h>#include "memory.h"#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= (~_BV(bit)))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//这两行为AVR中操作单个IO口的宏定义unsigned char sample_read,y;unsigned char DF_buffer[6]={0x55,0x54,0x53,0x51,0x50,0x00};unsigned char DF_Rebuffer[6]={};#define UDRE0 5#define RXC0 7void Usart0_init(void) ;//设置波特率9.6k,8位数据位,无校验,接收发送使能,1位停止位void Usart0_transmit(unsigned char c);unsigned char Usart0_receive(void);void Usart0_init(void)//7.3728Mhz频率,设置波特率9.6k,8位数据位,无校验,接收发送使能,1位停止位{//UCR0=0x00; //设置波特率之前先关闭串口UCSR0B=0B00000000;UCSR0A=0B00000000;UCSR0C=0B00000110;//UCSR0C=(1<<UCSZ00)|(1<<UCSZ01); //0x06 8位数据,1位停止位,无校验UBRR0H=0;UBRR0L=47;UCSR0B=(1<<RXEN0)|(1<<TXEN0); //发送接收使能,使用查询方式,故没有使能中断}void Usart0_transmit(unsigned char c) //查询方式发送接收字符函数{while( !(UCSR0A&(1<<UDRE0)));//等待发送缓冲区为空UDR0=c;//while(!(UCSR0A&(!<<TXC0)));// UDCR0=c;// SET_BIT(UCSR0A,TXC0); //将发送结束标志位清零}unsigned char Usart0_receive( void){while (!(UCSR0A&(1<<RXC0))) ;return UDR0;}//以上是串口发送接收函数//往SPI口写一个字节的数据void write_SPI(unsigned char data){SPDR = data;while (!(SPSR & 0x80));}//将保存在数组DF_buffer[]中的一页数据写入第二缓冲区后送入主存储区//(先擦除后写入模式,页地址范围0-4095)void DF_write_page(unsigned int page){unsigned int i;DF_SPI_ON;DF_wait_busy();DF_SELECT_1;//write_SPI(0x9f)write_SPI(BUFFER_2_WRITE);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);//write_SPI(DF_buffer[0]);/*for (i=0;i<528;i++)write_SPI(DF_buffer[i]);*/for (i=0;i<6;i++)write_SPI(DF_buffer[i]);DF_DESELECT_1;if (page<4096){DF_SELECT_1;write_SPI(B2_TO_MM_PAGE_PROG_WITH_ERASE);write_SPI((unsigned char)(page>>6));write_SPI((unsigned char)(page<<2));write_SPI(0x00);DF_DESELECT_1;DF_wait_busy();}DF_SPI_OFF;}//将指定主存储器页的数据转入第一缓冲区后读出,保存在DF_buffer[]数组中//(页地址范围0-4095)void DF_read_page(unsigned int page){unsigned int i;DF_SPI_ON;while(!(DF_STA_PORT & (1<< DF_STATE)));DF_SELECT_1;write_SPI(MM_PAGE_TO_B1_XFER);write_SPI((unsigned char)(page >> 6));write_SPI((unsigned char)(page << 2));write_SPI(0x00);DF_DESELECT_1;DF_wait_busy();DF_SELECT_1;write_SPI(BUFFER_1_READ);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);//write_SPI(0xFF);// y = SPDR;for (i=0;i<6;i++){write_SPI(0xFF);DF_Rebuffer[i] = SPDR;}DF_DESELECT_1;DF_SPI_OFF;}//读取状态寄存器//bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0//RDY/BUSY COMP 1 0 1 1 PROTECT PAGE SIZEunsigned char DF_read_reg(void){ unsigned char temp;DF_SPI_ON;DF_SELECT_1;write_SPI(READ_STATE_REGISTER);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);temp=SPDR;DF_DESELECT_1;DF_SPI_OFF;return temp;}//检查状态寄存器最高位是否为忙,并等待空闲void DF_wait_busy(void){ unsigned char state_reg=0x00;DF_SELECT_1;write_SPI(READ_STATE_REGISTER);write_SPI(0x00);write_SPI(0x00);write_SPI(0x00);while((state_reg&0x80) == 0){write_SPI(0x00);state_reg = SPDR ;}DF_DESELECT_1;}int main(void){ unsigned i;PORTE=0x4f;DDRE=0xf6;PORTB=0XFF;DDRB= 0B11110111;cbi(PORTB,5);_delay_us(10);sbi(PORTB,5);//AT45DB161 ResetUsart0_init();DF_SPI_ON;DF_wait_busy();DF_SELECT_1;write_SPI(0x9f);for(i=0;i<6;i++){DF_Rebuffer[i]=SPDR;}DF_DESELECT_1;DF_SPI_OFF;while(1){ for(i=0;i<6;i++){Usart0_transmit(DF_Rebuffer[i]);_delay_ms(100);}_delay_ms(2000);}}。
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*****************************************************/。
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#define F_CPU 8000000 //时钟源频率
int main(void)
{
while(1)//前后台系统
{
}
}
SIGNAL(SIG_INTERRUPT0) //外部中断INT0
{}
SIGNAL(SIG_INTERRUPT1) //外部中断INT1
{}
SIGNAL(SIG_OUTPUT_COMPARE2)// 定时器/计数器比较匹配中断{}
SIGNAL(SIG_OVERFLOW2)// 定时器/计数器2 溢出中断
{}
SIGNAL(SIG_INPUT_CAPTURE1)// 定时器/计数器2 输入捕获中断{}
SIGNAL(SIG_OUTPUT_COMPARE1A )//定时器/计数器1 比较匹配A {}
SIGNAL(SIG_OUTPUT_COMPARE1B )//定时器/计数器1 比较匹配B {}
SIGNAL(SIG_OVERFLOW1 )//定时器/计数器1 溢出中断
{}
SIGNAL(SIG_OVERFLOW0 )//定时器/计数器0 溢出中断
{}
SIGNAL(SIG_SPI )//SPI操作完成中断
{}
SIGNAL(SIG_UART_RECV)// USART 接收完成
{}
SIGNAL(SIG_UART_DATA)// USART 寄存器空
{}
SIGNAL(SIG_UART_TRANS)// USART 发送完成
{}
SIGNAL(SIG_ADC)// ADC转换完成
{}
SIGNAL(SIG_EEPROM_READY)// E2PROM 准备就绪{}
SIGNAL(SIG_COMPARATOR)// 模拟比较器中断
{}
SIGNAL(SIG_2WIRE_SERIAL)// TWI 中断
{}
SIGNAL(SIG_SPM_READY)// 写程序存储器准备好{}。