今天傍晚的时候,不死心,重心开始了那个IIC的测试,在又一遍仔细阅读文档后,重新理解控制寄存器中AA位的理解后,调整程序代码,重新测试。结果竟然正常了。这一次没有使用复杂的处理流程,直接在主程序中,以固定步骤循环处理以下逻辑:
发送开始信号
等待中断,以及状态=08H
如果正常,发送从机地址+写信号;不正常则发送异常信息及停止信号。
等待中断,以及状态=18H
如果正常,发送数据;不正常则发送异常信息及停止信号。
等待中断,以及状态=28H
如果正常,发送停止信号;不正常则发送异常信息及停止信号。
以下是代码:
/**
* 模块性能介绍
* 1、双线通讯,支持主机以及从机模式
* 2、支持多主机通讯时钟仲裁功能
* 3、支持地址可编程
* 4、支持标准速率(最多100kbps)和快速(最多400kbps)
*
* 以IIC方式驱动LCD1602,无视中断时IIC设备的状态值,只是按顺序发送数据
* ************************************************************************************
* 代码配置注意事项
* 1、当CPU运行在8M时,BOR必须使能为4.2V;
* 2、当CPU运行在4M时,BOR必须使能为3.0V及以上;
* 3、当CPU运行在2M时,BOR必须使能为2.0V及以上,常规情况下不建议关闭BOR;
* 4、使能BOR时除程序中修改,建议OPTION也配置相同电压。
* ************************************************************************************
* LCD1602模块: VCC - 5V
* (PCF8547) GND
* SCL - P3.2
* SDA - P3.3
* PCF8574T LCD1602
*================================================================================
* P7 DB7
* P6 DB6
* P5 DB5
* P4 DB4
* P3 控制背光灯
* P0 RS
* P1 RW
* P2 CS
*================================================================================
* LCD1602的操作
* 写指令: RS=0, RW=0, CS(E)上升沿
* 写数据: RS=1, RW=0, CS(E)上升沿
*================================================================================
* LCD1602的操作指令
* Bit RS RW 7 6 5 4 3 2 1 0
*-----------------------------------------------------------------------------------
* 1.清除显示 0 0 0 0 0 0 0 0 0 1
* 2.光标返回 0 0 0 0 0 0 0 0 1 *
* 3.设输入模式 0 0 0 0 0 0 0 1 I/D S I/D:光标移动方向,1-右移;0-左移
* S:屏幕上所有文字是否左移或右移,1表示有效,0表示无效
* 4.显示开关 0 0 0 0 0 0 1 D C B D=1开显示,D=0关显示
* C=1显示光标,C=0关闭光标
* B=1光标闪烁,B=0光标不闪烁
* 5.光标字符移位 0 0 0 0 0 1 S/C R/L * * S/C 1-显示移动的文字,0-移动光标
* R/L 左右方向
* 6.设置功能 0 0 0 0 1 DL N F * * DL: 1-4位总线;0-8位总线
* N: 1-双行显示;0-单行显示
* F: 1-5X10点阵, 0-5x7点阵
* 7.设置字符发生器地址 0 0 0 1 字符发生器RAM
* 8.设置数据存储器地址 0 0 1 显示数据存储器地址
*-----------------------------------------------------------------------------------
* 9.读忙标志或地址 0 1 BF 计数器地址
* 10.写数到CGRAM或DDRAM 1 0 要写的数据内容
* 11.从CGRAM或DDRAM读 1 1 读出的数据
*===================================================================================
* 数据指针设置 80H + 地址码(0-27H(第一行),40H-67H(第二行))
** LCD1602 四线驱动方式下,一个字节数据传输2回
**/
#include"holychip_define.h"
//--------------OLED参数定义---------------------
#define LINE_1_ADDR 0x40
#define LINE_2_ADDR 0x80
#define WIDTH 128
#define HEIGHT 32
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
#define IIC_SLAVE_ADDR 0x4E //IIC器件地址:
#define LCD_ADDR_W 0x4E
#define LCD_ADDR_R 0x4F
#define IIC_STATUS_START_OK 0x08 // START发送完成后的状态(ACK应答)(STA,STO,SI,AA)=(1,0,0,X)
#define IIC_STATUS_REPEAT_START_OK 0x10 // START发送完成后的状态(ACK应答)(STA,STO,SI,AA)=(1,0,0,X)
#define IIC_STATUS_WADDR_ACK_OK 0x18 // 向从机发送写指令+地址,发送完成后的状态(ACK应答)(STA,STO,SI,AA)=(X,0,0,X)
#define IIC_STATUS_DATA_ACK_OK 0x28 // 向从机发送数据,完成后的状态(ACK应答)(STA,STO,SI,AA)=(0,0,0,X)
#define IIC_STATUS_WADDR_NACK_OK 0x20 // 向从机发送写指令+地址,发送完成后的状态(NACK应答)(STA,STO,SI,AA)=(X,0,0,X)
#define IIC_STATUS_DATA_NACK_OK 0x30 // 向从机发送数据,完成后的状态(NACK应答)(STA,STO,SI,AA)=(0,0,0,X)
//unsigned char HEXCHR[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
unsigned char iic_status = 0; // 每次发送完成后获得的IIC状态码
unsigned char iic_next_status = 0; // 本次发送产生中断时,期待的状态值,若与实际值不一致,表示出错
unsigned char iic_error_flag = 0; // 发送处理出现错误的标志
unsigned char iic_interrupt_flag = 0; // 发生IIC中断的标志
//unsigned char guc_Uartbuf = 0; //UART判断标志位
//unsigned char guc_Uartflag = 0; //用于存放接收收据
unsigned int gms=0; // 延时变量
//unsigned char guc_lcdchar[33]={'\0'}; // 保存液晶显示用数据
//unsigned char lcdchar_addr = 0; // LCD显示字符的位置0-15为第一行,16-31为第二行
/***************************************************************************************
* @说明 1毫秒单位的延时
* @参数 ms 毫秒数
* @返回值 无
* @注 比较准确,
***************************************************************************************/
void delay_ms(unsigned int ms) {
gms=ms;
while(gms > 0) {
// 等待 gms = 0
}
}
/***************************************************************************************
* @说明 10微秒单位的延时
* @参数 ms 毫秒数
* @返回值 无
* @注 不准确,
***************************************************************************************/
void delay_10us(unsigned int wm) {
unsigned char a,b,c;
for(c=0; c<wm; c++) {
for(b=0; b<40; b++) {
}
}
}
/***************************************************************************************
* @说明 取得十六进制字符
* @参数 chr 字符
* h_l_flag 0 - 低四位对应16进制字符;1 - 高四位对应字符
* @返回值 无
* @注 无
***************************************************************************************/
unsigned char toHexChar(unsigned char chr, unsigned char h_l_flag) {
unsigned char val = chr;
unsigned char result=0;
if (h_l_flag) {
val = (val & 0xF0)>>4;
} else {
val = val & 0x0f;
}
switch (val) {
case 0:
result = '0';break;
case 1:
result = '1';break;
case 2:
result = '2';break;
case 3:
result = '3';break;
case 4:
result = '4';break;
case 5:
result = '5';break;
case 6:
result = '6';break;
case 7:
result = '7';break;
case 8:
result = '8';break;
case 9:
result = '9';break;
case 10:
result = 'A';break;
case 11:
result = 'B';break;
case 12:
result = 'C';break;
case 13:
result = 'D';break;
case 14:
result = 'E';break;
case 15:
result = 'F';break;
default:
result = '-';break;
}
return result;
}
/***************************************************************************************
* @说明 判断字符是否能显示
* @参数 chr
* @返回值 0 - 不可显示; 1 - 可显示
* @注
***************************************************************************************/
unsigned char isDispChar(unsigned char chr) {
if (chr >= 32 && chr <= 126) {
return 1;
}
return 0;
}
/***************************************************************************************
* @说明 串口发送一个字符
* @参数 chr 字符
* @返回值 无
* @注 无
***************************************************************************************/
void send_char(unsigned char chr) {
SBUF = chr; //发送8位串口数据
while(!TXIF);
TXIF = 0; //清除发送中断标志位
}
/***************************************************************************************
* @说明 串口发送一个字符,以十六进制方式表示
* @参数 chr 字符
* @返回值 无
* @注 无
***************************************************************************************/
void send_char_hex(unsigned char chr) {
SBUF = '0';
while(!TXIF);
TXIF = 0; //清除发送中断标志位
SBUF = 'x';
while(!TXIF);
TXIF = 0; //清除发送中断标志位
SBUF = toHexChar(chr, 1);
while(!TXIF);
TXIF = 0; //清除发送中断标志位
SBUF = toHexChar(chr, 0);
while(!TXIF);
TXIF = 0; //清除发送中断标志位
SBUF = ' ';
while(!TXIF);
TXIF = 0; //清除发送中断标志位
}
/***************************************************************************************
* @说明 串口发送一个字符,以十进制方式表示
* @参数 chr 字符
* @返回值 无
* @注 无
***************************************************************************************/
void send_char_dec(unsigned char chr) {
if (chr > 99) {
SBUF = toHexChar(chr/100, 0);
while(!TXIF);
TXIF = 0; //清除发送中断标志位
}
if (chr > 9) {
SBUF = toHexChar((chr%100)/10, 0);
while(!TXIF);
TXIF = 0; //清除发送中断标志位
}
SBUF = toHexChar(chr%10, 0);
while(!TXIF);
TXIF = 0; //清除发送中断标志位
}
/***************************************************************************************
* @说明 串口发送一个字符串
* @参数 str 字符串
* @返回值 无
* @注 无
***************************************************************************************/
void send_str(unsigned char *str) {
unsigned char chr = '\0';
while (chr=*str) {
send_char(chr);
str++;
}
}
/***************************************************************************************
* @说明 中断服务函数
* @参数 无
* @返回值 无
* @注 包含定时器2中断和IIC中断
***************************************************************************************/
void interrupt all_isr(void) {
// // IIC中断
if (IICIF) {
PORTA0 = ~PORTA0;
// // 保存状态
// iic_status = IICSTA;
// send_char('[');
// send_char_hex(iic_status);
// send_char(']');
//
// // 建立中断发生标志
// iic_interrupt_flag = 1;
//
// // 判断是不是期待的状态
// if (iic_status != iic_next_status) {
// // 不是,表示出错了,这个时候处理可以终止了
// iic_error_flag = 1;
// }
//
// //清除中断标志位
// IICIF = 0;
}
// // 串口接收中断,收到的数据存入数据缓冲区(对应两行32个字符)
// if(RXIF) {
// guc_Uartbuf = SBUF; // 转存8位串口接收数据
// guc_Uartflag = 1; // 接收中断标志
//
// // 如果是可显示的字符,保存
// if (isDispChar(guc_Uartbuf)) {
// guc_lcdchar[lcdchar_addr] = guc_Uartbuf;
// lcdchar_addr = (lcdchar_addr+1)%32; // 显示位置指向下一个
// }
//
// SCON &= ~0x10; //禁止串口继续继续接收数据
// RXIF = 0; //清除接收中断标志位
// }
// 定时器0中断
if(T0IF) {
T0 = 0xF0; //T0定时时间1ms
if (gms>0) {
gms=gms-1;
}
T0IF = 0; //清除T0中断标志位
}
}
/***************************************************************************************
* @说明 向IIC总线发送开始信号
* @参数 无
* @返回值 0 - 失败(中断产生的状态值不对);1 - 正常
* @注 发送完开始信号后,等待中断,并产生预期的状态值
***************************************************************************************/
unsigned char I2cStart(unsigned char next_status) {
//send_str((unsigned char *)"\r\n<I2cStart>");
IICIF = 0; // 清除中断标志
IICCON |= 0x20; // 启动发送:STA,STO,SI,AA=1,0,0,X
iic_next_status = next_status; // 设置中断发生后期待的状态值 08H
// 等待中断发生,改变状态值
while (iic_interrupt_flag==0) {
// 等待中断发生,此处最好建立溢出时间,避免进入死循环
}
// 清除中断发生过的标志
iic_interrupt_flag=0;
// 从串口发送当前状态值
//send_char_hex(iic_status);
if (iic_status != iic_next_status) {
// 状态值不对,不是预期的状态
return 0;
}
// 正常
return 1;
}
/***************************************************************************************
* @说明 向IIC总线发送数据,
* @参数 dat 要发送给PCF8574T的数据或者地址
* next_status 期待收到的状态值
* @返回值 0 - 失败(中断产生的状态值不对);1 - 正常
* @注 发送完开始信号后,等待中断,并产生预期的状态值
* 数据将通过PCF8574T反映到P7~P0引脚上,给LCD1602用
* 带ACK的应答场合,发送完成后应该=28H;NACK场合,状态值=30H
***************************************************************************************/
unsigned char I2cSendByte(unsigned char dat, unsigned char next_status) {
//send_str((unsigned char *)"\r\n<I2cSendByte>");
IICDAT = dat; // 要发送给PCF8574T的数据或者地址
//IICCON |= 0x40; // 启动IIC模块(以为之前好像不发送数据) -- 错误,会导致一直IIC中断
// 等待中断发生,改变状态值
while (iic_interrupt_flag==0) {
// 等待中断发生,此处最好建立溢出时间,避免进入死循环
}
// 清除中断发生过的标志
iic_interrupt_flag=0;
// 从串口发送当前状态值
//send_char_hex(iic_status);
if (iic_status != next_status) {
// 状态值不对,不是预期的状态
return 0;
}
// 正常返回
return 1;
}
/***************************************************************************************
* @说明 向IIC总线发送停止信号
* @参数 无
* @返回值 无
* @注 无
***************************************************************************************/
void I2cStop(void) {
//send_str((unsigned char *)"\r\n<I2cStop>");
// 发出停止信号
IICCON |= 0x10; // STO=1,发送停止信号 STA,STO,SI,AA=0,1,0,X
}
/***************************************************************************************
* @说明 通过IIC发送一个字节给PCF8574T,PCF8574T是作为IIC从机存在的
* @参数 dat 呈现到 P7 ~ P0管脚上,连接到LCD引脚
* P7 -- LCD160-DB7
* P6 -- LCD160-DB6
* P5 -- LCD160-DB5
* P4 -- LCD160-DB4
* P3 -- LCD1602-背光灯
* P2 -- LCD1602-E
* P1 -- LCD1602-RW
* P0 -- LCD1602-RS
* @返回值 无
* @注 发送给LCD1602,要通过PCF8574T实现
***************************************************************************************/
unsigned char send_pcf8574Byte(unsigned char dat) {
send_str((unsigned char *)"\r\n<send_pcf8574Byte start>");
// 初始化监视用变量
iic_interrupt_flag = 0;
iic_error_flag = 0;
// 发送IIC的起始信号
if (I2cStart(IIC_STATUS_START_OK) == 0) {
//if (I2cStart(IIC_STATUS_REPEAT_START_OK) == 0) {
// 如果发送起始信号失败,处理中止
// 发送当前的IIC中断状态值
//send_str((unsigned char *)"IIC status=");
// 当前状态值
//send_char_hex(iic_status);
//send_str((unsigned char *)"\r\n");
// // 发送结束信号
// I2cStop();
//
// return 0;
goto send_pcf8574Byte_end;
}
IICCON &=~ 0x20; // 不发送起始信号,因为是持续发送, STA=0
// 发送地址信息(PCF8574T占用的地址)
// 发送写从机指令,写指令+从机地址, STA,STO,SI,AA=X,0,0,X
if (I2cSendByte(IIC_SLAVE_ADDR, IIC_STATUS_WADDR_ACK_OK) == 0) {
// 发送失败,处理中止
// 发送当前的IIC中断状态值
//send_str((unsigned char *)"IIC status=");
// 当前状态值
//send_char_hex(iic_status);
//send_str((unsigned char *)"\r\n");
// // 发送结束信号
// I2cStop();
// return 0;
goto send_pcf8574Byte_end;
}
// 发数据给PCF8574T,转交给LCD1602
if (I2cSendByte(dat, IIC_STATUS_DATA_ACK_OK) == 0) {
// 发送失败,处理中止
// 发送当前的IIC中断状态值
//send_str((unsigned char *)"IIC status=");
// 当前状态值
//send_char_hex(iic_status);
//send_str((unsigned char *)"\r\n");
// // 发送结束信号
// I2cStop();
//
// return 0;
}
send_pcf8574Byte_end:
// 发送结束信号
I2cStop();
send_str((unsigned char *)"\r\n<send_pcf8574Byte end>");
return 1;
}
/***************************************************************************************
* @说明 向LCD1602发送指令
* @参数 cmd 指令
* @返回值 无
* @注 通过PCF8574T转成引脚输出,适配LCD1602方式
* -----------------------------------
* dat PCF8574T LCD1602
*------------------------------------
* D7 P7 DB7
* D6 P6 DB6
* D5 P5 DB5
* D4 P4 DB4
* D3 P3 控制背光灯
* D2 P0 RS
* D1 P1 RW
* D0 P2 E
***************************************************************************************/
void write_lcd1602_cmd(unsigned char cmd) {
unsigned char cmd1, cmd2;
cmd1=cmd|0x0f;
// 发送高4位
send_pfc8574Byte(cmd1 & 0xfc); // 11111100 : CS=1,RW=0, RS=0
delay_10us(1);
send_pfc8574Byte(cmd1 & 0xf8); // 11111000 : CS=0,RW=0, RS=0
// 发送低4位,要移位到高4位位置上
cmd2=cmd<<4;
cmd2=cmd2|0x0f;
send_pfc8574Byte(cmd2 & 0xfc); // 11111100 : CS=1,RW=0, RS=0
delay_10us(1);
send_pfc8574Byte(cmd2 & 0xf8); // 11111000 : CS=0,RW=0, RS=0
}
/***************************************************************************************
* @说明 向LCD1602发送数据
* @参数 dat 指令
* @返回值 无
* @注 通过PCF8574T转成引脚输出,适配LCD1602方式
* -----------------------------------
* dat PCF8574T LCD1602
*------------------------------------
* D7 P7 DB7
* D6 P6 DB6
* D5 P5 DB5
* D4 P4 DB4
* D3 P3 控制背光灯
* D2 P0 RS
* D1 P1 RW
* D0 P2 E
***************************************************************************************/
void write_lcd1602_data(unsigned char dat) {
unsigned char dat1, dat2;
dat1=dat|0x0f;
// 发送高4位
send_pfc8574Byte(dat1 & 0xfd); // 11111101 : CS=1,RW=0, RS=1
delay_10us(1);
send_pfc8574Byte(dat1 & 0xf9); // 11111001 : CS=0,RW=0, RS=1
// 发送低4位,要移位到高4位位置上
dat2=dat<<4;
dat2=dat2|0x0f;
send_pfc8574Byte(dat2 & 0xfd); // 11111101 : CS=1,RW=0, RS=1
delay_10us(1);
send_pfc8574Byte(dat2 & 0xf9); // 11111001 : CS=0,RW=0, RS=1
}
/***************************************************************************************
* @说明 初始化LCD
* @参数 无
* @返回值 无
* @注 无
***************************************************************************************/
void lcd_init(void) {
send_str((unsigned char *)"\r\n<lcd_init>");
//write_lcd1602_cmd(0x33); // 设置显示 4 (0x38:8)
//write_lcd1602_cmd(0x32); // 设置4线控制
write_lcd1602_cmd(0x28); // 设置16*2, 5*7, 4线初始化
write_lcd1602_cmd(0x06); // 地址加1,数据不移动,地址移动
//write_lcd1602_cmd(0x0C); // 不显示光标,光标不闪烁
//write_lcd1602_cmd(0x0f); // 显示光标,光标闪烁
write_lcd1602_cmd(0x01); // 清屏
write_lcd1602_cmd(0x80); // 起始地址
delay_ms(5);
}
//Y为显示指针的位置,即为各行的第几个位置,X选行
//col:0-15
//row:0-1
/***************************************************************************************
* @说明 设置显示位置
* @参数 row 垂直位置(0~1)
* col 水平位置(0~15)
* @返回值 无
* @注 无
***************************************************************************************/
void lcd1602_GotoXY(unsigned char row, unsigned char col) {
send_str((unsigned char *)"\r\n<lcd1602_GotoXY>row=");
send_char_hex(row);
send_str((unsigned char *)",col=");
send_char_dec(col);
if(row == 0) write_lcd1602_cmd(0x80 + col);
if(row == 1) write_lcd1602_cmd(0x80 + 0x40 + col);
}
/***************************************************************************************
* @说明 使LCD在当前位置显示字符串
* @参数 str 字符串
* @返回值 无
* @注 无
***************************************************************************************/
void LCD1602_Display_NoXY(unsigned char *str) {
send_str((unsigned char *)"\r\n<LCD1602_Display_NoXY>str=");
send_str(str);
while(*str != '\0') {
write_lcd1602_data(*str);
str++;
}
}
/***************************************************************************************
* 用IO模拟IIC方式通讯
***************************************************************************************/
/***************************************************************************************
* @说明 向IIC总线发送开始信号
* @参数 无
* @返回值 无
* @注 SCL=1时,SDA由1->0的跳变,就是起始信号
***************************************************************************************/
void io_start(void) {
PORTC0=1;
delay_10us(5);
PORTC2=1;
delay_10us(5);
PORTC0=0; // SDA->0
delay_10us(5);
PORTC2=0; // SCL=0,准备下一个时钟信号(准备变高),
delay_10us(5);
}
/***************************************************************************************
* @说明 向IIC总线发送结束信号
* @参数 无
* @返回值 无
* @注 当SCL=1时,SDA由0->1的跳变,就是结束信号
***************************************************************************************/
void io_stop(void) {
PORTC0=1;
delay_10us(5);
PORTC2=1;
delay_10us(5);
PORTC0=0;
delay_10us(5);
PORTC2=0;
delay_10us(5);
}
/***************************************************************************************
* @说明 向IIC总线发送数据
* @参数 dat 数据
* flg 等待从机应答 0-NACK应答,1-ACK应答
* @返回值 无
* @注
***************************************************************************************/
unsigned char io_sendbyte(unsigned char dat, unsigned char ack_nack_flag) {
unsigned char a=0,b=0;
// 使PORT0为输出模式
TRISC=0x05;
// 发出数据,在SDA准备好数据,SCL由0->1时,SDA数据被接收
for(a=0;a<8;a++) {
PORTC0=dat>>7;
dat=dat<<1;
delay_10us(5);
PORTC2=1;
delay_10us(5);
PORTC2=0;
delay_10us(5);
}
// 等待应答
PORTC0=1;
// 使PORT0为输入模式
TRISC=0x04;
// 等待从机使ACK=0
delay_10us(5);
PORTC2=1;
delay_10us(5);
if (ack_nack_flag) {
// ACK应答
while(PORTC0) {
b++;
if(b>200) {
// 超时,没有收到ACK信号
PORTC2=0;
delay_10us(5);
return 0;
}
}
} else {
// NACK应答
}
PORTC2=0;
delay_10us(5);
return 1;
}
/***************************************************************************************
* @实现效果 IIC主机发送与接收
***************************************************************************************/
void main() {
//unsigned char arry[]="This is test!";
//unsigned char old_ptr = 0; // LCD显示字符位置
unsigned char sta=0;
/************************************系统初始化****************************************/
OSCCON = 0x04; //Fosc=32M Fcpu=4M(Fosc4分频 2T)
/************************************IO初始化*****************************************/
ANSELA = 0x01; //PA0设为数字形式
TRISA = 0x01; //PA0为输出口-中断指示
ANSELC = 0xFF; //PC口的B0、B1、B2、B4、B6、B7为数字模式,对TSSOP20封装,只有PC0,PC1,PC2,PC4
// 对TSSOP20封装,PORTC2、PORTD4、PORTB6、可对应于IIC_SDA;
// PORTC2和PORTB7可对应于IIC_SCK;
// 此处使用PORTC2和PORTC0映射为IIC的SCK和SDA
IICMAP = 0x11;
// PORTC2为输出模式
//TRISC = 0x04;
TRISC = 0x05; // PC2和PC0输出模式
/************************************IIC初始化*****************************************/
// IICCON构成:CR2\IICEN\STA\STO\-\AA\CR1\CR0
// 0x40: CR2~CR0:000,Fcpu=4M模式下,通讯速度=15.63KHz
// IICEN=1,启动IIC模块
// STA=0,不发送起始信号
// STO=0,不发送停止信号
// AA=1,回复ACK(SDA上为低电平)
IICCON = 0x44; //启动IIC模块
/********************T0配置初始化********************/
OPTION = 0X07; // 分频寄存器配置256分频
T0CS = 0; // T0 模式选择寄存器:定时器模式,计数时钟Fcpu,休眠和绿色模式下停止
T0OSCEN = 0; // 禁止定时器模块0使用计数时钟
T0SE = 0; // 定时器模式,计数时钟Fcpu
/********************UART配置初始化********************/
ANSELB = 0xC0; //PB7 PB6设为数字模式
TRISB = 0x40; //PB7设为输入模式 PB6设为输出模式
INTMAP = 0x20;
UARTMAP = 0x50; //映射 PB7口作为RX PB6口作为TX
// 波特率等设置
BRTH = 0xFF;
BRTL = 0xE6; //Baudrate_9600
SCON2 = 0x24; //UART功能选择 8位
SCON |= 0x10; //使能UART接收
/********************中断设置********************/
T0IE = 1; //打开T0中断
//IICIE = 1; //允许IIC中断
PEIE = 1; //允许未屏蔽中断
GIE = 1; //允许总中断
send_str((unsigned char *)"\r\n<main>");
// // 字符显示变量初始化
// guc_lcdchar[32]='\0';
//
// // 初始化LCD
// lcd_init();
//
// // 定位显示位置为第一行、第一列
// lcd1602_GotoXY(0,0);
// write_lcd1602_data('A');
//
// // 定位显示位置为第二行、第一列
// lcd1602_GotoXY(1,0);
// LCD1602_Display_NoXY(arry);
// 关闭中断指示LED
PORTA0 = 1;
while(1) {
send_str((unsigned char *)"\r\n");
// 清除IIC中断标志
IICIF = 0;
// 使IIC外设向IIC总线发送“START”信号
IICCON |= 0x20; // 产生开始信号
send_char_hex(0xA1);
// 等待中断发生
while (!IICIF);
iic_status=IICSTA;
send_char_hex(iic_status);
if(iic_status == 0x08) {
send_char_hex(0xA2);
// 发送子机地址
IICCON &=~ 0x20; // STA=0,禁止继续发START信号
IICCON |= 0x04; // AA=1,确认子机回复ACK信号?
IICDAT = IIC_SLAVE_ADDR;
IICIF = 0;
} else {
send_char_hex(0xA0);
IICCON |= 0x10; // 停止信号
}
// 等待中断发生
while (!IICIF);
iic_status=IICSTA;
send_char_hex(iic_status);
if(iic_status == 0x18) {
send_char_hex(0xA3);
// 发送数据
IICCON &=~ 0x20; // STA=0,禁止继续发START信号
IICCON |= 0x04; // AA=1,确认子机回复ACK信号?
IICDAT = 0x32;
IICIF = 0;
} else {
send_char_hex(0xA0);
IICCON |= 0x10; // 停止信号
}
// 等待中断发生
while (!IICIF);
iic_status=IICSTA;
send_char_hex(iic_status);
if(iic_status == 0x28) {
send_char_hex(0xA9);
} else {
send_char_hex(0xA0);
}
IICCON |= 0x10; // 停止信号
// //lcd1602_GotoXY(0,0);
// if(guc_Uartflag) {
// // 收到串口中断
// guc_Uartflag = 0; // 清除串口接收中断标志
// SCON |= 0x10; //UART接收使能
// }
//
// // 上位机发来可显示的字符?
// if (lcdchar_addr != old_ptr) {
// if (old_ptr<16) {
// lcd1602_GotoXY(0, old_ptr);
// write_lcd1602_data(guc_lcdchar[old_ptr]);
// } else {if (old_ptr<32 && old_ptr>15) {
// lcd1602_GotoXY(1, old_ptr-16);
// write_lcd1602_data(guc_lcdchar[old_ptr]);
// }
// }
//
// // 更新为最新位置
// old_ptr = (lcdchar_addr%32);
// old_ptr++;
//
// // 通过发送简单的数据,测试
// //send_pcf8574Byte(old_ptr);
// io_start();
// io_sendbyte(LCD_ADDR_W, 1); // 写器件的物理地址
// io_sendbyte(old_ptr, 1);
// io_stop();
//
// // 延迟一段时间,方便示波器连续观测波形
// // 每5秒,PCF8574的P7~P0输出脚发生变化,类似于流水灯
// delay_ms(200);
}
}因为比较匆忙,代码没有整理,中间许多注释掉的代码依旧保留着。
由串口获得调试信息 如下:
可以看到 ,状态值的确是按照08H -> 18H -> 28H的顺序在变化着,这和主机发送模式下IIC处理中的状态值变化是一致的。
后面如果有时间,会继续编写驱动iic lcd1602的测试程序 。

我要赚赏金
