Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2012876
  • 博文数量: 356
  • 博客积分: 8284
  • 博客等级: 中将
  • 技术积分: 4580
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-15 20:25
个人简介

天行健,君子以自强不息

文章分类

全部博文(356)

文章存档

2018年(1)

2016年(4)

2015年(13)

2014年(14)

2013年(2)

2012年(25)

2011年(43)

2010年(65)

2009年(189)

分类: BSD

2010-01-21 16:21:26

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();//清除看门狗定时器,喂狗
 }
}

代码见上,此处使用的是定期清除看门狗定时器(即喂狗),发现数码管稳定地显示出40.

 

 

假如我们不定期清除看门狗定时器,即把上面红色的WDR()注释掉,显示效果就会发生改变。

 

此时由于没有定期清除看门狗定时器会发现数码管显示出的40会每隔一秒钟闪动一下。(因为WDTCR=0x0e,即WDP2=WDP1=1,WDP0=0,即看门狗定时器的溢出周期是一秒,故而看门狗会每隔一秒使单片机复位)

阅读(2644) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~