atmega16L相关程序(测试成功)
前一段时间在网上买了一块atmega16L的芯片,自己做了一个简单的最小系统版,同时配合自己以前做的数码管显示模块写了一些相关的程序,现在总结如下。
1、数码管动态显示
#include
#define uchar unsigned char
#define uint unsigned int
#define wei PORTD
#define duan PORTB
uchar t1[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82}; //0-9
uchar t2[]={0x70,0xb0,0xd0,0xe0};
uchar t3[]={0x0e,0x0d,0x0b,0x07};
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=190;y>0;y--);
}
void init()
{
DDRB=0XFF;
DDRD=0XFF;
}
void display(uint z)
{
wei =t3[3];
duan=t1[z/1000];
delay(5);
wei =t3[2];
duan=t1[(z%1000)/100];
delay(5);
wei =t3[1];
duan=t1[(z%100)/10];
delay(5);
wei =t3[0];
duan=t1[z%10];
delay(5);
}
void main()
{
uchar i,j;
j=0;
init();
while(1)
{
display(9876);
}
}
说明一下,由于我的数码管的段选线和标准的那种接法不一样,因而段码就相应的不同。数码管都是有三极管做位选,采用的是动态扫描的显示方法。
2、定时器0中断,数码管显示
#include
#define uchar unsigned char
#define uint unsigned int
#define wei PORTD
#define duan PORTB
uchar t1[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82}; //0-9
uchar t2[]={0x70,0xb0,0xd0,0xe0};
uchar t3[]={0x0e,0x0d,0x0b,0x07};
uint i;
uint j;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=200;y>0;y--);
}
void init_display()
{
DDRB=0XFF;
DDRD=0XFF;
}
void timer0_init()
{
TCNT0=0X00;
TCCR0=0X03;
TIMSK=0X01;
SREG=0X80;
}
void init_device()
{
init_display();
timer0_init();
}
void display(uint z)
{
wei =t3[3];
duan=t1[z/1000];
delay(5);
wei =t3[2];
duan=t1[(z%1000)/100];
delay(5);
wei =t3[1];
duan=t1[(z%100)/10];
delay(5);
wei =t3[0];
duan=t1[z%10];
delay(5);
}
void main()
{
init_device();
while(1)
{
display(j);
}
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0=0X00;
i++;
if(i>=50)
{
i=0;
j++;
}
}
3、AD转换(外部5v参考电压)
#include
#define uchar unsigned char
#define uint unsigned int
#define wei PORTD
#define duan PORTB
uchar t1[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82}; //0-9
uchar t11[]={0x40,0x7c,0x09,0x03,0x26,0x12,0x10,0x47,0x00,0x02};//0-9共阳,带小数点
uchar t2[]={0x70,0xb0,0xd0,0xe0};
uchar t3[]={0x0e,0x0d,0x0b,0x07};
uint i;
uint j;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=200;y>0;y--);
}
void init_display()
{
DDRB=0XFF;
DDRD=0XFF;
}
void timer0_init()
{
TCNT0=0X00;//定时器0的定时初值
TCCR0=0X03;//定时器0的计数预分频取64
TIMSK=0X01;//使能T/c0中断
SREG=0X80;//使能总中断
}
void adc_init()
{
ADCSRA=0Xe3;//自由转换方式,8分频,若为0xC7,则为单次转换,输入电压改变后,输出不变
ADMUX=0X07;//外部参考电压,输入为通道7
}
void init_device()
{
init_display();
timer0_init();
adc_init();
}
uint adc_convert()
{
uint temp1,temp2;
temp1=(uint)ADCL;
temp2=(uint)ADCH;
temp2=(temp2<<8)+temp1;
return temp2;
}
uint conv(uint i)
{
long x;
uint y;
x=(5000*(long)i)/1023;
y=(uint) x;
return y;
}
void display(uint z)
{
wei =t3[3];
duan=t11[z/1000];
delay(5);
wei =t3[2];
duan=t1[(z%1000)/100];
delay(5);
wei =t3[1];
duan=t1[(z%100)/10];
delay(5);
wei =t3[0];
duan=t1[z%10];
delay(5);
}
void main()
{
uint adval;
init_device();
while(1)
{
if(j>10)
{
j=0;
adval=adc_convert();
adval=conv(adval);
}
display(adval);
}
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0=0X00;
i++;
if(i>=10)
{
i=0;
j++;
}
}
4、EEPROM读写试验
/*atmega16的eeprom是一个16位的地址和一个8位的数据
心得与体会:
1、记得以前用51操作at24c04时忽视了一个问题,就是只管往存储器里面写数据而不管数据是否写得下的问题。例如这款单片机中自带的eeprom是8位的数据,当写入的数据大于255时,就会出错,发现自己写入的数据不能正确的读出来
2、一个程序可以有多个任务,可以用定时器中断让cpu在不同的任务(功能函数之间切换),从而更加均匀合理地完成硬件资源的分配,达到更好的效果
*/
#include
#define uchar unsigned char
#define uint unsigned int
#define wei PORTD
#define duan PORTB
uchar t1[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82}; //0-9
uchar t11[]={0x40,0x7c,0x09,0x03,0x26,0x12,0x10,0x47,0x00,0x02};//0-9共阳,带小数点
uchar t2[]={0x70,0xb0,0xd0,0xe0};
uchar t3[]={0x0e,0x0d,0x0b,0x07};
uint i;
uint j;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=200;y>0;y--);
}
void init_display()
{
DDRB=0XFF;
DDRD=0XFF;
}
void timer0_init()
{
TCNT0=0X00;//定时器0的定时初值
TCCR0=0X03;//定时器0的计数预分频取64
TIMSK=0X01;//使能T/c0中断
SREG=0X80;//使能总中断
}
void adc_init()
{
ADCSRA=0Xe3;//自由转换方式,8分频,若为0xC7,则为单次转换,输入电压改变后,输出不变
ADMUX=0X07;//外部参考电压,输入为通道7
}
void init_device()
{
init_display();
timer0_init();
adc_init();
}
uint adc_convert()
{
uint temp1,temp2;
temp1=(uint)ADCL;
temp2=(uint)ADCH;
temp2=(temp2<<8)+temp1;
return temp2;
}
uint conv(uint i)
{
long x;
uint y;
x=(5000*(long)i)/1023;
y=(uint) x;
return y;
}
void display(uint z)
{
wei =t3[3];
duan=t1[z/1000];
delay(5);
wei =t3[2];
duan=t1[(z%1000)/100];
delay(5);
wei =t3[1];
duan=t1[(z%100)/10];
delay(5);
wei =t3[0];
duan=t1[z%10];
delay(5);
}
/*写eeprom子函数*/
void w_eep(uint add,uint dat)//dat为代写数据,add为eeprom某单元地址
{
while(EECR&(1< EEAR=add;//设定单元地址
EEDR=dat;//将数据写入eeprom
EECR|=(1< EECR|=(1<}
/*读eeprom子函数*/
uint r_eep(uint add)
{
while(EECR&(1< EEAR=add;//设定单元地址
EECR|=(1< return EEDR;//返回读出的数据
}
void main()
{
uint value;
init_device();
w_eep(488,123);
while(1)
{
display(value);
if(j>25)
{
j=0;
r_eep(488);//使用中断的方法定时从eeprom中读出数据,其余时间执行display函数
value=r_eep(488);
}
}
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0=0X00;
i++;
if(i>=10)
{
i=0;
j++;
}
}
5、看门狗试验
#include
#include
#define uint unsigned int
#define uchar unsigned char
#define xtal 8
#define wei PORTD
#define duan PORTB
uchar t1[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82}; //0-9
uchar t2[]={0x70,0xb0,0xd0,0xe0};
uchar t3[]={0x0e,0x0d,0x0b,0x07};
uint i;
uint j;
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=200;y>0;y--);
}
void init_display()
{
DDRB=0XFF;
DDRD=0XFF;
}
void display(uint z)
{
wei =t3[3];
duan=t1[z/1000];
delay(5);
//delay_ms(10);
wei =t3[2];
duan=t1[(z%1000)/100];
delay(5);
//delay_ms(10);
wei =t3[1];
duan=t1[(z%100)/10];
delay(5);
//delay_ms(10);
wei =t3[0];
duan=t1[z%10];
delay(5);
//delay_ms(10);
}
void delay_1ms()
{
uint i;
for(i=1;i<(uint)(xtal*143-2);i++);
}
void delay_ms(uint n)
{
uint i=0;
while(i {
delay_1ms();
i++;
}
}
void watchdog_init(void)
{
WDR();
WDTCR=0x0e;
}
void init_device()
{
watchdog_init();
init_display();
}
/*
void timer0_init()
{
TCNT0=0X00;
TCCR0=0X03;//定时器0的计数预分频取64
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr()
{
SREG=0X80;//重新开放总中断,确保计时准确
TCNT0=0X000X00;
j++;
if(j>100)
{
j=0;
i++;
}
}
*/
void main()
{
i=0;
init_device();
while(1)
{
display(i);
//delay_ms(3);
//WDR();//清除看门狗定时器,喂狗
}
}
代码见上,此处使用的是定期清除看门狗定时器(即喂狗),发现数码管稳定地显示出4个0.
假如我们不定期清除看门狗定时器,即把上面红色的WDR()注释掉,显示效果就会发生改变。
此时由于没有定期清除看门狗定时器会发现数码管显示出的4个0会每隔一秒钟闪动一下。(因为WDTCR=0x0e,即WDP2=WDP1=1,WDP0=0,即看门狗定时器的溢出周期是一秒,故而看门狗会每隔一秒使单片机复位)