搜索
bottom↓
回复: 24

ATmega48/SPI/74HC595/74HC165驱动1602LCD、键盘,LCD可以正反180度连接,共占用4个IO口

[复制链接]

出0入0汤圆

发表于 2006-9-18 00:39:40 | 显示全部楼层 |阅读模式
为了大家交流的方便,我将写几个常用的函数,并且尽量的兼容各种C编译器,包括



1:读74HC165函数    data=read165();



2:写74HC595函数    write595(data);



3:1602LCD初始化函数    lcd_init();



4:1602LCD光标定位函数    lcd_gotoxy(8,1);   //定位到8列1行



5:写一个数据到1602LCD函数    lcd_data('A');   //显示'A'



6:写一个指令到1602LCD函数    lcd_dictate(1);  //LCD清屏指令是'1'



请留意下面的例子

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

 楼主| 发表于 2006-9-18 00:40:02 | 显示全部楼层
读74HC165/写74HC595示例



硬件说明:J2的4个跳线都插上



#include <mega48.h>

#include <595-165.h>

#include <delay.h>   



void main(void)

{           

  spiinit();                     //spi初始化

  while(1)

       {        

         unsigned char data,i;

         data=read165();        //通过硬件SPI读取74HC165的数据

         if(data==254) i+=1;

         write595(i);           //通过硬件SPI把数据写入74HC595  

         delay_ms(100);

       }   

}//end





下面是头文件"595-165.h"的内容





//定义一个全局变量来记忆最后一次写入74HC595的数据

//目的是读74HC165时保持74HC595的数据不发生改变

//变量名复杂一点目的是避免和其它变量混淆  



unsigned char DATA_74HC595_74HC165;   

void spiinit(void)  //spi初始化

{

  PORTB&=0b11000011;

  DDRB|= 0b00101100;

  SPCR=80;

}



void write595(unsigned char LED_DATA) //写数据到74HC595函数

{

  SPDR=LED_DATA;                      //开始发送数据

  while((SPSR>>7)==0);                //等待发送接收结束

  DATA_74HC595_74HC165=LED_DATA;      //记忆最后一次发送的数据

  LED_DATA=SPDR;                      //读,是为了清零中断标志

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC595的数据  

}  

  

unsigned char read165(void)           //读74HC165函数

{

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC165的数据

  SPDR=DATA_74HC595_74HC165;          //载入74HC595最后一次的数据,目的是读取74HC165

  while((SPSR>>7)==0);                //等待发送接收结束

  return SPDR;                        //返回值是SPI接收到74HC165的数据

}

出0入0汤圆

 楼主| 发表于 2006-9-18 00:40:29 | 显示全部楼层
1602LCD程序示例



#include <mega48.h>

#include <delay.h>

#include <595-165.h>

#include <1602lcd.h>



void main(void)

{         

  spiinit();              //spi初始化

  lcd_init();             //LCD初始化

  while(1)

       {        

      

         lcd_dictate(1);  //LCD清屏指令是'1'

         delay_ms(500);   

         lcd_data('A');   //显示'A'

         delay_ms(500);

         lcd_gotoxy(8,1); //定位到8列1行

         lcd_data(48);    //显示'0',0的ASCII值是48

         delay_ms(500);

       }   

}//end







下面是“1602lcd.h”头文件内容



//使用“1602lcd.h”文件前请先包含“595-165.h”文件

//由于LCD内部的处理速度比较慢,所以必须加入适当延时

//LCD可以旋转180度连接,程序只需修改SPI数据方向即可

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

#include <delay.h>



void lcd_dictate(unsigned char dictate_data) //写LCD指令的函数

{   

  unsigned char temp_data;

  temp_data=dictate_data&240; //求高4位,        

  write595(temp_data+8);      //写DB7/DB6/DB5/DB4/E=1/RW=0/RS=0/VO=0

  write595(temp_data);        //E由1变为0,其它数据不变  

  temp_data=dictate_data<<4;  //求低4位......

  write595(temp_data+8);

  write595(temp_data);

  delay_ms(2);                //写指令后一定要适当延时

}

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

void lcd_init(void)           //LCD初始化函数

{   

  delay_ms(20);

  write595(56); write595(48); //固定初始化数据

  delay_ms(6);  

  write595(56); write595(48); //固定初始化数据

  delay_ms(2);   

  write595(56); write595(48); //固定初始化数据  

  delay_ms(2);

  write595(40); write595(32); //固定初始化数据  

  delay_ms(2);

  lcd_dictate(40);            //数据_4位/2行/5*7象素

  lcd_dictate(12);            //显示_开/光标_关

}

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

//列/行定位函数,最开头的地址是0列0行

void lcd_gotoxy(unsigned char x, unsigned char y)  //列/行定位函数

{      

  unsigned char xy;

  if(x<=19 && y<=3)           //防止输入的数据不正确

    {     

      if(y==0) xy=x+128;      //第0行的地址是从128开始

      if(y==1) xy=x+192;      //第1行......

      if(y==2) xy=x+148;

      if(y==3) xy=x+212;

      lcd_dictate(xy);

    }

}

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

void lcd_data(unsigned char byte_data)  //写显示数据函数

{   

  unsigned char temp_data;

  temp_data=(byte_data&240)+2; //求高4位,同时RS=1     

  write595(temp_data+8);       //写DB7/DB6/DB5/DB4/E=1/RW=0/RS=0/VO=0

  write595(temp_data);         //E由1变为0,其它数据不变  

  temp_data=(byte_data<<4)+2;  //求低4位......

  write595(temp_data+8);

  write595(temp_data);

  delay_ms(1);                 //写显示数据也要适当延时

}

出0入0汤圆

 楼主| 发表于 2006-9-18 00:40:58 | 显示全部楼层
实时时钟PCF8563例子,由1602LCD显示



#include <mega48.h>

#include <delay.h>

#include <595-165.h>

#include <1602lcd.h>

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

//软件模拟I2C初始化,由代码向导产生

#asm

   .equ __i2c_port=0x08 ;PORTC

   .equ __sda_bit=4

   .equ __scl_bit=5

#endasm

#include <i2c.h>

#include <pcf8563.h>

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

void main(void)

{      

  spiinit();                                //spi初始化

  lcd_init();                               //LCD初始化

  i2c_init();                               //I2C通讯初始化

  rtc_init(0,RTC_CLKOUT_1,RTC_TIMER_OFF);   //PCF8563初始化  

  // rtc_set_time(16,19,0);  //(时,分,妙) //设置时间

  // rtc_set_date(19,8,2006);//(日,月,年) //设置日期   



while(1)

     {

        unsigned char M,D,h,m,s;            //月/日/小时/分钟/秒钟

        unsigned int  Y;                    //年   

        

        lcd_dictate(1);                     //LCD清屏

        lcd_gotoxy(4,1);                    //定位到4列1行



        rtc_get_date(&D,&M,&Y);             //读日/月/年

        rtc_get_time(&h,&m,&s);             //读小时/分钟/秒钟

        

        lcd_data(h/10%10+48);               //显示小时的"十位"

        lcd_data(h%10+48);                  //显示小时的"个位"

        

        lcd_data('-');                      //显示'-'

        

        lcd_data(m/10%10+48);               //显示分钟

        lcd_data(m%10+48);

        

        lcd_data('-');

        

        lcd_data(s/10%10+48);               //显示秒钟

        lcd_data(s%10+48);

        

        delay_ms(100);

        

     }

}

出0入0汤圆

 楼主| 发表于 2006-9-18 00:47:40 | 显示全部楼层






点击此处打开armok01128967.pdf

出0入0汤圆

发表于 2006-9-18 17:59:05 | 显示全部楼层
这个要收藏的

出0入0汤圆

 楼主| 发表于 2006-9-24 21:32:44 | 显示全部楼层
M8实验板 74HC165/74HC595读写函数 AVRGCC + AVR studio





芯片:ATmega48



时钟:不限



J2的4个跳线短接



-------------------------------------------------------------------------



主程序



#include <avr/io.h>

#include "595-165.h"

#include <avr/delay.h>   



void main(void)

{           

  spiinit();                     //spi初始化

  while(1)

       {        

         unsigned char data,i;

         data=read165();        //通过硬件SPI读取74HC165的数据

         if(data==254) i+=1;

         write595(i);           //通过硬件SPI把数据写入74HC595  

         _delay_ms(10);

       }   

}//end



-----------------------------------------------------------------------------



595-165.h头文件



unsigned char DATA_74HC595_74HC165;   

void spiinit(void)  //spi初始化

{

  PORTB&=0b11000011;

  DDRB|= 0b00101100;

  SPCR=80;

}



void write595(unsigned char LED_DATA) //写数据到74HC595函数

{

  SPDR=LED_DATA;                      //开始发送数据

  while((SPSR>>7)==0);                //等待发送接收结束

  DATA_74HC595_74HC165=LED_DATA;      //记忆最后一次发送的数据

  LED_DATA=SPDR;                      //读,是为了清零中断标志

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC595的数据  

}  

  

unsigned char read165(void)           //读74HC165函数

{

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC165的数据

  SPDR=DATA_74HC595_74HC165;          //载入74HC595最后一次的数据,目的是读取74HC165

  while((SPSR>>7)==0);                //等待发送接收结束

  return SPDR;                        //返回值是SPI接收到74HC165的数据

}

出0入0汤圆

 楼主| 发表于 2006-9-24 21:33:30 | 显示全部楼层
M8实验板 1602LCD驱动 AVRGCC + AVR studio





主程序



-----------------------------------------------------------------------



#include <avr/io.h>

#include "595-165.h"

#include "1602lcd.h"



void main(void)

{         

  spiinit();              //spi初始化

  lcd_init();             //LCD初始化

  while(1)

       {        

      

         lcd_dictate(1);  //LCD清屏指令是'1'

         _delay_ms(250);   

         lcd_data('A');   //显示'A'

         _delay_ms(250);

         lcd_gotoxy(8,1); //定位到8列1行

         lcd_data(48);    //显示'0',0的ASCII值是48

         _delay_ms(250);

       }   

}//end







-------------------------------------------------------------------------



595-165.h头文件



-------------------------------------------------------------------------



unsigned char DATA_74HC595_74HC165;   

void spiinit(void)  //spi初始化

{

  PORTB&=0b11000011;

  DDRB|= 0b00101100;

  SPCR=80;

}



void write595(unsigned char LED_DATA) //写数据到74HC595函数

{

  SPDR=LED_DATA;                      //开始发送数据

  while((SPSR>>7)==0);                //等待发送接收结束

  DATA_74HC595_74HC165=LED_DATA;      //记忆最后一次发送的数据

  LED_DATA=SPDR;                      //读,是为了清零中断标志

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC595的数据  

}  

  

unsigned char read165(void)           //读74HC165函数

{

  PORTB&=251; PORTB|=4;               //PB2输出一个负脉冲,刷新74HC165的数据

  SPDR=DATA_74HC595_74HC165;          //载入74HC595最后一次的数据,目的是读取74HC165

  while((SPSR>>7)==0);                //等待发送接收结束

  return SPDR;                        //返回值是SPI接收到74HC165的数据

}



------------------------------------------------------------------------



1602lcd.h头文件



------------------------------------------------------------------------



//使用“1602lcd.h”文件前请先包含“595-165.h”文件

//由于LCD内部的处理速度比较慢,所以必须加入适当延时

//LCD可以旋转180度连接,程序只需修改SPI数据方向即可

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

#include <avr/delay.h>



void lcd_dictate(unsigned char dictate_data) //写LCD指令的函数

{   

  unsigned char temp_data;

  temp_data=dictate_data&240; //求高4位,        

  write595(temp_data+8);      //写DB7/DB6/DB5/DB4/E=1/RW=0/RS=0/VO=0

  write595(temp_data);        //E由1变为0,其它数据不变  

  temp_data=dictate_data<<4;  //求低4位......

  write595(temp_data+8);

  write595(temp_data);

  _delay_ms(2);                //写指令后一定要适当延时

}

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

void lcd_init(void)           //LCD初始化函数

{   

  _delay_ms(20);

  write595(56); write595(48); //固定初始化数据

  _delay_ms(6);  

  write595(56); write595(48); //固定初始化数据

  _delay_ms(2);   

  write595(56); write595(48); //固定初始化数据  

  _delay_ms(2);

  write595(40); write595(32); //固定初始化数据  

  _delay_ms(2);

  lcd_dictate(40);            //数据_4位/2行/5*7象素

  lcd_dictate(12);            //显示_开/光标_关

}

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

//列/行定位函数,最开头的地址是0列0行

void lcd_gotoxy(unsigned char x, unsigned char y)  //列/行定位函数

{      

  unsigned char xy;

  if(x<=19 && y<=3)           //防止输入的数据不正确

    {     

      if(y==0) xy=x+128;      //第0行的地址是从128开始

      if(y==1) xy=x+192;      //第1行......

      if(y==2) xy=x+148;

      if(y==3) xy=x+212;

      lcd_dictate(xy);

    }

}

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

void lcd_data(unsigned char byte_data)  //写显示数据函数

{   

  unsigned char temp_data;

  temp_data=(byte_data&240)+2; //求高4位,同时RS=1     

  write595(temp_data+8);       //写DB7/DB6/DB5/DB4/E=1/RW=0/RS=0/VO=0

  write595(temp_data);         //E由1变为0,其它数据不变  

  temp_data=(byte_data<<4)+2;  //求低4位......

  write595(temp_data+8);

  write595(temp_data);

  _delay_ms(1);                 //写显示数据也要适当延时

}

出0入0汤圆

 楼主| 发表于 2006-9-25 23:04:41 | 显示全部楼层
M8实验板 74HC165/74HC595读写函数 BASCOM-AVR





$regfile = "m48def.dat"                                     ' 定义目标单片机是ATmega48

$crystal = 1000000                                          ' 时钟是1000000Hz



Dim X As Byte                                               '定义2个变量

Dim Data_74hc595_74hc165 As Byte



Declare Sub Spi_init                                        '声明一个过程,没有返回值

Declare Sub Write595(data_74hc595 As Byte)                  '声明一个过程,没有返回值

Declare Function Read165() As Byte                          '声明一个函数,有返回值



'------------------------------------------------------------------------------------



Spi_init                                                    '硬件SPI初始化

Do

  X = Read165()

  Write595 X

Loop

End



'-------------------------------------------------------------------------

Sub Spi_init                                                'spi初始化

  Portb = Portb And &B11000011

  Ddrb = Portb Or &B00101100

  Spcr = 80

End Sub

'------------------------------------------------------------------------------------

Sub Write595(data_74hc595 As Byte)                          '写数据到74HC595函数

  Spdr = Data_74hc595                                       'SPI开始发送数据

  While Spsr.7 < 1                                          '等待发送接收结束

  Wend

  Data_74hc595_74hc165 = Data_74hc595                       '记忆最后一次发送的数据

Data_74hc595 = Spdr                                        '读,是为了清零中断标志

  Portb.2 = 0 : Portb.2 = 1                                 'Pb2输出一个负脉冲 , 刷新74hc595的数据

End Sub

'-----------------------------------------------------------------------------------------------------

Function Read165() As Byte                                  '读74HC165函数

  Portb.2 = 0 : Portb.2 = 1                                 'PB2输出一个负脉冲,刷新74HC165的数据

  Spdr = Data_74hc595_74hc165                               '载入74HC595最后一次的数据,目的是读取74HC165

  While Spsr.7 < 1                                          '等待发送接收结束

  Wend

  Read165 = Spdr                                            '返回值是SPI接收到74HC165的数据

End Function

出0入0汤圆

发表于 2006-9-26 15:08:05 | 显示全部楼层
谢谢,板子买了,例程也照收。

出0入0汤圆

发表于 2007-1-3 12:00:11 | 显示全部楼层
LCD可以旋转180度安装,而且程序只需修改一个寄存器的值就可以了,不错,的确是一个非常好创意

出0入0汤圆

发表于 2010-3-29 10:40:45 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-6-8 05:57:31 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-10-17 14:41:07 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-12-31 14:44:32 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-12-31 19:07:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-15 15:10:03 | 显示全部楼层
MARK.Good Job!

出0入0汤圆

发表于 2011-10-13 13:55:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-27 11:17:49 | 显示全部楼层
我来挖一下。

出0入0汤圆

发表于 2012-1-30 14:05:33 | 显示全部楼层
记号

出0入0汤圆

发表于 2012-8-21 06:08:51 | 显示全部楼层
非常好,谢谢

出0入0汤圆

发表于 2013-1-25 13:00:31 | 显示全部楼层

出0入0汤圆

发表于 2013-3-6 20:30:40 来自手机 | 显示全部楼层
支持下!!!

出0入0汤圆

发表于 2013-7-1 17:15:32 | 显示全部楼层
好好学习,天天向上
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 23:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表