1602四线驱动

#include <ioavr.h> 
#include <ina90.h>

#define uchar unsigned char

#define LCD_PORT  PORTA
#define LCD_DDR   DDRA
#define LCD_PIN   PINA

#define LCD_DATA       ((1<<0)|(1<<1)|(1<<2)|(1<<3))


#define EN_SET PORTC|=(1<<6);//en拉高
#define EN_CLR PORTC&=~(1<<6);//en拉低
#define RS_SET PORTC|=(1<<4);
#define RS_CLR PORTC&=~(1<<4);
#define RW_SET PORTC|=(1<<5);
#define RW_CLR PORTC&=~(1<<5);



#define SETBIT(x,y)   (x|=(1<<y))      //set bit y in byte x
#define CLRBIT(x,y)   (x&=(~(1<<y)))   //clear bit y in byte xx

void DelayUs(unsigned char us)//delay us
{
 unsigned char uscnt;
 uscnt=us>>1;/* Crystal frequency in 12MHz*/
 while(--uscnt);
}

//<<<<<<<<<<<<<<<<<<<<LCD检查忙程序>>>>>>>>>>>>>>>>>>>>>>
void LCD_Check_busy(void)
{
  RS_CLR;
  RW_SET;
  LCD_DDR = 0x00;
  _NOP();
  EN_SET;
  while(LCD_PIN & 0x08)
  {
    ;
  }
  EN_CLR;
  LCD_DDR = 0xff; 
}

//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------


//设置所需函数

//写数据线命令(四线模式数据要分两次写)
void out_dataline(uchar dat)
{
  DelayUs(10000);// LCD_Check_busy();
  
  LCD_PORT &= 0x0F;
  LCD_PORT |=  dat&0xF0;       //写高四位数据
  EN_SET;//SETBIT(LCD_PORT, EN);  //EN=1
   _NOP();
  EN_CLR;//CLRBIT(LCD_PORT, EN);  //EN=0
  
  _NOP();
  
  LCD_PORT &= 0x0F;
  LCD_PORT |=  (dat<<4)&0xF0;       //写高四位数据
  
  EN_SET;//SETBIT(LCD_PORT, EN);  //EN=1
  _NOP();
  EN_CLR;//CLRBIT(LCD_PORT, EN);  //EN=0
}



//一、写指令函数
void write_command(unsigned char com)
{
  DelayUs(10000);// LCD_Check_busy();
 
  RS_CLR;//CLRBIT(LCD_PORT, RS); //RS=0
  out_dataline(com);
}

//二、写数据函数(四线模式数据要分两次写)

void write_data(unsigned char data)
{
  DelayUs(10000);// LCD_Check_busy();
  RS_SET;//SETBIT(LCD_PORT, RS); //RS=1
  out_dataline(data);
}


//三、初始化LCD1602函数
void LCD_init(void)
{
  LCD_DDR = 0xFF;       //设为输出
  DDRC=0XFF;
  
  RW_CLR;//CLRBIT(LCD_PORT, RW); //设为永远W状态


  write_command(0x28);

  DelayUs(100000);
  
   write_command(0x0D);
   DelayUs(1000000);
  write_command(0x01);  //显示开--对应开关显示控制指令
   DelayUs(10000);
  write_command(0x06);  //清屏--对应清屏指令
  
  

}


//四、写地址函数

//--------------------------------------------------------------------------------

//要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符
//1602液晶内部显示地址

//比如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?
//这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该?
//?1000000B(40H)+10000000B(80H)=11000000B(C0H)

//--------------------------------------------------------------------------------

void LCD_set_addr(unsigned char x, unsigned char y) //x:0~15,y:0~1
{
  if(y)
  {
    write_command(0xc0 + x);  //第二行显示
  }
  else
  {
    write_command(0x80 + x);  //第一行显示
  }
}



//五、写字符函数
void LCD_write_char(unsigned char X, unsigned char Y,
                    unsigned char data) //列x=0~15,行y=0,1
{
  LCD_set_addr(X, Y);   //写地址
  write_data(data);
}


//六、写字符串函数

void LCD_write_string(unsigned char X, unsigned char Y, unsigned char* s) //列x=0~15,行y=0,1
{
  LCD_set_addr(X, Y);   //写地址
  while(*s)   // 写显示字符
  {
    write_data(*s);
    s ++;
  }

}
原文地址:https://www.cnblogs.com/ppStudio/p/4209829.html