这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 芯圣HC18M003的IIC主机发送模式的调试笔记之三-测试正常完结

共6条 1/1 1 跳转至

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

专家
2023-10-31 20:27:51   被打赏 50 分(兑奖)     打赏

今天傍晚的时候,不死心,重心开始了那个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);
    }
}

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

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

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

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






关键词: 菜鸟学单片机    

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

看着不错


专家
2023-11-18 09:22:38     打赏
3楼

学习学习


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

学习一下了


高工
2023-12-22 08:32:07     打赏
5楼

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


专家
2023-12-27 14:56:13     打赏
6楼

非常详细的分析,


共6条 1/1 1 跳转至

回复

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