1、#define LCD1602_DB = P0 //后面没有 ; 长点记性!
2、mask>>=1 //被自己写成 mask >>1 编译不报错,自己检查还逻辑正确,找了好久才找到错误!!
main().c 文件 I2C子函数
传输byte
起始位
结束位
确定应答值ack
#include <reg52.h>
#include <intrins.h>
#define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}
sbit I2C_SCL = P3^7;
sbit I2C_SDA = P3^6;
bit I2CAddressing(unsigned char addr);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
void main()
{
bit ack;
unsigned char str[10];
InitLcd1602(); //初始化液晶
ack = I2CAddressing(0x50); //查询地址为0x50的器件
str[0] = '5'; //将地址和应答值转换为字符串
str[1] = '0';
str[2] = ':';
str[3] = (unsigned char)ack + '0';
str[4] = '\0';
LcdShowStr(0, 0, str); //显示到液晶上
ack = I2CAddressing(0x62); //查询地址为0x62的器件
str[0] = '6'; //将地址和应答值转换为字符串
str[1] = '2';
str[2] = ':';
str[3] = (unsigned char)ack + '0';
str[4] = '\0';
LcdShowStr(8, 0, str); //显示到液晶上
while (1);
}
/* 产生总线起始信号 */
void I2CStart()
{
I2C_SDA = 1; //首先确保SDA、SCL都是高电平
I2C_SCL = 1;
I2CDelay();
I2C_SDA = 0; //先拉低SDA
I2CDelay();
I2C_SCL = 0; //再拉低SCL
}
/* 产生总线停止信号 */
void I2CStop()
{
I2C_SCL = 0; //首先确保SDA、SCL都是低电平
I2C_SDA = 0;
I2CDelay();
I2C_SCL = 1; //先拉高SCL
I2CDelay();
I2C_SDA = 1; //再拉高SDA
I2CDelay();
}
/* I2C总线写操作,dat-待写入字节,返回值-从机应答位的值 */
bit I2CWrite(unsigned char dat)
{
bit ack; //用于暂存应答位的值
unsigned char mask; //用于探测字节内某一位值的掩码变量
这面的函数通过探测掩码来实现一个byte的从高->低输出 思路很好。
下面的函数单独看,因为我在他身上浪费了两个小时!!!! mask>>=1 这个>>= 的等号千万不能丢!否则死循环
for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次进行 注意这里mask>>=1 看仔细了有一个等号!!!
{
if ((mask&dat) == 0) //该位的值输出到SDA上
I2C_SDA = 0;
else
I2C_SDA = 1;
I2CDelay();
I2C_SCL = 1; //拉高SCL
I2CDelay();
I2C_SCL = 0; //再拉低SCL,完成一个位周期
}
I2C_SDA = 1; //8位数据发送完后,主机释放SDA,以检测从机应答
I2CDelay();
I2C_SCL = 1; //拉高SCL
ack = I2C_SDA; //读取此时的SDA值,即为从机的应答值
I2CDelay();
I2C_SCL = 0; //再拉低SCL完成应答位,并保持住总线
return ack; //返回从机应答值
}
/* I2C寻址函数,即检查地址为addr的器件是否存在,返回值-从器件应答值 */
bit I2CAddressing(unsigned char addr)
{
bit ack;
I2CStart(); //产生起始位,即启动一次总线操作
ack = I2CWrite(addr<<1); //高7位表示地址所以左移了一下,因寻址命令的最低位
//为读写位,用于表示之后的操作是读或写
I2CStop(); //不需进行后续读写,而直接停止本次总线操作
return ack;
}
液晶程序 LCD1602.c文件 子函数
写cmd
读状态确定ready
写dat
确定显示光标位置
集成 确定光标并显示dat
初始化
#include<reg52.h>
#define LCD1602_DB P0 //注意#define 定义后面没有;
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
/* 等待液晶准备好 */
void LCDWaitReady()
{
unsigned char sta;
LCD1602_DB = 0xff;
LCD1602_RS = 0;
LCD1602_RW = 1;
do{
LCD1602_E = 1;
sta = LCD1602_DB; //读取状态字
LCD1602_E = 0;
}while(sta&0x80); //bit7 等于1表示液晶正忙
}
/* 向LCD1602写入一个字节命令,cmd为待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
LCDWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
/* 向LCD1602写入一个字节数据,dat为待写入命令值 */
void LcdWriteDat(unsigned char dat)
{
LCDWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
/* 设置显示器RAM起始位置,亦即光标位置,(x,y)为对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x,unsigned char y)
{
unsigned char addr;
if(y==0)
addr = 0x00 + x;
else
addr = 0x40 + x;
LcdWriteCmd(addr|0x80);
}
/* 在液晶屏幕上显示字符串,(x,y) 对应屏幕坐标上的起始坐标,str为字符串指针*/
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)
{
LcdSetCursor(x,y);
while(*str != '\0') //用'\0'来判断字符串是否截止
{
LcdWriteDat(*str++); //str先把地址对应内容传递给dat输出后,str++;
}
}
/* 初始化1602液晶 */
void InitLcd1602()
{
LcdWriteCmd(0x38); //16*2显示,5*7点阵,8位数据接口
LcdWriteCmd(0x0c); //显示区开,光标关闭
LcdWriteCmd(0x06); //文字不动,地址自动加一
LcdWriteCmd(0x01); //清屏
}