论坛» 嵌入式开发» 国产MCU

芯圣HC18M003的IIC主机发送模式的调试笔记之三-测试正常完结

专家
2023-12-22 11:28 1楼

今天傍晚的时候,不死心,重心开始了那个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>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"); 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"); 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"); // 发出停止信号 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"); // 初始化监视用变量 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"); 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"); //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\nrow="); 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\nstr="); 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
"); // // 字符显示变量初始化 // 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); } }

因为比较匆忙,代码没有整理,中间许多注释掉的代码依旧保留着。

由串口获得调试信息 如下:

图片1.png可以看到 ,状态值的确是按照08H -> 18H -> 28H的顺序在变化着,这和主机发送模式下IIC处理中的状态值变化是一致的。

后面如果有时间,会继续编写驱动iic lcd1602的测试程序 。



工程师
2023-11-09 08:26 2楼

看着不错

专家
2023-11-18 09:22 3楼

学习学习

工程师
2023-12-07 08:41 4楼

学习一下了

高工
2023-12-22 08:32 5楼

不错,非常详细,感谢分享

专家
2023-12-27 14:56 6楼

非常详细的分析,

共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]