分享

AVR单片机ATMEGA16 1602液晶驱动程序及心得

 共同成长888 2015-07-19

AVR单片机ATMEGA16 1602液晶驱动程序及心得 

     首先,祝福各位同仁,光棍节快乐!   
     今天,给我最好的节日礼物就是,我自己研发的AVR微控制器芯片开发板,1602液晶屏实验成功!我很欣慰.写了一整天的程序,反复实验,最终在凌晨0点.终于成功了. 
    在此过程中,最大的问题莫过于那个所谓配套的1602液晶屏数据手册!这个手册简直是误人子弟,里面资料写的很含糊.并且有错误,而导致我反复试验失败,最终,我使用了通用的1602液晶屏数据手册,才得以成功.
      我自制的AVR开发板尺寸和我买的51开发板差不多大小,ATmega16最小系统,8位数码管,蓝光流水灯,isp编程接口.过载保护保险丝,两个74hc573锁存器.1602液晶屏都已焊接完成,万用板是12X18cm的单孔玻纤板(质量不太好,便宜没好货).现在我才发现不够用,模块数量相同的两块实验板,手工焊接的一定要比机器印刷的大2~3倍才行.....
     没办法,我只能用5X7cm的万用板做小模块,ADC模块,DS1302时钟模块,激光二极管模块等等,然后用杜邦线把它们和AVR核心板链接起来,目前计划是这样的,往往计划很丰满,实际很骨感,伤脑筋啊,,,
    此次,首次接触了12864大液晶,能显示中文,和超声波测距传感器,这得好好研究一下,我一直想要了解一下2.4g无线传输模块,和陀螺仪传感器,还有GPS模块,不过那些还早,把AVRATMEGA16学的差不多了,再了解,也不迟.
/*
          Program name:  AVR  ATMEGA16 1602驱动程序

 
 初次实验通过时间:  2013-11-11 00:04:01  ^_^  ;
 
 注意:在bysy()函数中严重出错!下次注意!
 
 while((PINA&0x80)==0x80); 此语句检测到PA7为零时终止循环;表明空
 闲状态
 
          心得:
       AVR单片机的IO口位操作比较复杂,
   由三个寄存器控制IO口的输出与输入;    
   DDRn(输出/输入控制) 寄存器;
PORTn(输出时控制数据,输入时控制内部上拉电阻)寄存器;
PINn(用于读取IO口数据)寄存器; 
               最终校验通过时间:  2013年11月12日15:12:28
          
*/
#include <iom16v.h>
#include <macros.h>

#define uint8  unsigned char 
#define uint16 unsigned int

//========IO口位操作========================================

void rs(uint8 h)   //数据/指令选择操作;

  if(h)
    PORTB|=1<<3;  //置一;
  else
    PORTB&=~(1<<3); //清零;
}

void rw(uint8 h)   //读/写选择操作;
{
   if(h==0)
    {
 PORTB&=~(1<<4);  //清零;
}
   else
    {
 DDRA=0X00;
 PORTA=0XFF;
 PORTB|=1<<4;  //置一;
}

}

void e(uint8 h)   //传输使能位;
{
  if(h)
    {
 PORTB|=1<<5;   //置一;
}
  else
    PORTB&=~(1<<5);//清零;

}


//========================================================

void  ddra(uint8 h)   //PA口输入输出函数;
{
    if(h)
{
 DDRA=0XFF;      //输出模式;
 PORTA=0xff; 
}
else
 
{DDRA=0X00; PORTA=0XFF; } //输入模式并且有上拉;

}

void busy()    //繁忙检测;
{
   ddra(0);    //设置PA口为输入,有上拉;
   do
   { 
     e(0);     //传输使能为0;
rs(0);    //指令;
rw(1);    //读;
e(1);     //e为高电平;
   
   }while((PINA&0x80)==0x80);//如果读到数据是01111111,表示空闲状态,跳出循环;
    e(0);
ddra(1);   //PA口输出状态;
 
}

void delay()  //小延时;
{
  uint8 j=0;
  j=1;

}

void w_cmd(uint8 cmd)
{
  busy();     //繁忙检测通过时,PA口为输出状态,默认输出0xff;
  PORTA=cmd;  //向PA口装载数据;
  rs(0);      //指令;
  rw(0);      //写入;
  e(1);       //传输使能脉冲高;
  delay();    //延时;
  e(0);       //传输使能脉冲低;

}

void w_dat(uint8 dat)
{
  busy();     //繁忙检测通过时,PA口为输出状态,默认输出0xff;
  PORTA=dat;  //向PA口装载数据;
  rs(1);      //数据;
  rw(0);      //写入;
  e(1);       //传输使能脉冲高;
  delay();    //延时;
  e(0);       //传输使能脉冲低;

}

void init_1602()
{
   
   w_cmd(0x3c);  //写入显示设置:8位数据,两行,5x10显示;
   w_cmd(0x0c);  //整屏显示,光标不闪,字符不闪;
   w_cmd(0x06);  //写入一个数据时地址自动加一.整屏不移动;
   w_cmd(0x01);  //写入'清屏'指令;
   
 
}

 

void display(uint8 addr ,uint8 dat )//可在任意位置显示字符,
{                                   //addr地址,dat数据;
  w_cmd(addr);
  w_dat(dat);
}

 

void main(void)        //====主函数=================
{  
    uint8 i=0, j=0x80,ak[]="I'am iron man!"; //要显示的字符串"我是钢铁侠!"
    uint8 sj[]="2013-11-11 ^_^";  //今天的日期;
    uint16 s=0;                  //16位的变量;
    DDRB=0XFF;           //PB口输出状态;
PORTB=0X03;  //PB0=1;PB1=1;   
DDRA=0XFF;    //PA口输出状态;     
PORTA=0X00;   //8个数码管共阴极为'0'.八位阳极为'0';
PORTB=0X00;   //锁存数据;
 
    init_1602();   //液晶屏初始化;
 
 w_cmd(0x81);  //初始化完成以后先发送要写入的数据的显示位置.
               //0x81是第一行,第1位. 0x80是第0位;
while(ak[i]!='\0')  //将ak[]数组内的所有数据发送;
  {  
 w_dat(ak[i++]);    //每发送一个字节数据,数据的存储地址自动加一;
 for(s=0;s<50000;s++);  //延时一下,字符会有一个,一个显示的效果;
    }
w_cmd(0xc1);   //发送第二排的数据地址,接下来字符会在第二排第1位开始显示;
i=0;           
while(sj[i]!='\0')   //将sj[]数组内的数据全部发完;
{
  w_dat(sj[i++]);
  for(s=0;s<25000;s++);   //效果延时;

 
}
  
 
while(1);       //死亡循环;

}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多