打印
[学习资料]

PIC单片机之I2C通信(主模式)

[复制链接]
1460|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kxsi|  楼主 | 2019-7-25 11:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
我们今天来讲I2C通信。那I2C通信的特点是什么能。我们一般使用的串口 (半双工异步串行通信)与I2C 有什么区别呢。

    串口(半双工异步串行通信):就是好像朋友在对话。我可以主动和你讲话,你也可以主动和我讲话。

    I2C:就好像上下级对话。一个领导面对一个或者多个员工。只有领导主动说话的份儿,下面的员工不能主动说话。只有领导问了,员工才能答。

    I2C通信

    I2C通信只需要两个引脚 一个数据线,一个时钟线。 数据线顾名思义就是用来传递数据的。时钟线是来决定数据传输的速度。当时钟线为高电平时,数据线上的数据才会被认为是有效的。

   数据线的 数据有四种状态 : 高电平,低电平,下降沿(高电平变低电平),上升沿(低电平变高电平)。

   当时钟线为高电平时候这四种状态分别代表:1,0,起始位,停止位。

   如果我们发送的数据为十六进制的0x88即是二进制为10001000的数据是怎么发送的呢?我们就以此为例一步步讲解。

     


使用特权

评论回复
沙发
kxsi|  楼主 | 2019-7-25 11:06 | 只看该作者
1,常态

       在不发送任何数据的时候数据线和时钟线都为高电平。所以I2C通信在硬件设计,需要在数据线和时钟线上分别加上两个上拉电阻。

     2,起始

     当开始发送数据的时候 时钟线为高同时数据线从 高电平变低电平,代表开始发送数据。

     3,发送数据

     发送完起始位后 时钟线变为低电平,在发送每一位的数据之前时钟线有一段低电平,主要的作用是给数据线做电平变化用的。

     我们现在要发送的第一个位是 1。

    1、时钟线为低,同时数据线从低电平变成高电平。

    2、接着时钟线变为高电平,此时接收方得知时钟线为高,便查看数据线为高电平 说明数据为 “1”。

    3、我们要发送的下一个位为0。时钟线再变为低,同时数据线从高电平变成低电平。

    4、接着时钟线再变为高电平,此时接收方得知时钟线为高,便查看数据线为低电平 说明数据为"0"。

    5、再下一个为还为0。时钟线再变为低,同时数据线一直保持低电平不变。

    6、接着时钟线再变为高电平,此时接收方得知时钟线为高,便查看数据线为低电平 说明数据为”0“。

    以此类推 直到发送完所有的位。

   4,应答(ACK)

    当接收方接收完一个字节的数据就要告诉对方我收到了。接收方如果接收到数据则控制数据线输出低电平。否则为高电平。

   5,停止

     没有下一个字节要发送,最后时钟线变为高电平后,数据线从低电平变为高电平。代表数据发送停止。

使用特权

评论回复
板凳
kxsi|  楼主 | 2019-7-25 11:07 | 只看该作者

实例讲解: 使用单片机使用 RSM2257 电子音量控制芯片来控制音量。一个按键按下,声音变大,一个按键按下,声音变小。在加上一个按键,控制一个LED亮灭的程序。而且音量掉电保存。

介绍RSM2257.

    子地址

      在I2C通信中每一个从设备都有个子地址,因为I2C支持一主多从,也就是说有一个主机可以连接多个从机。每个从机,都有个地址。就好像每个人的名字一样来区分不同的设备。下面是RSM2257接口协议,首先先发送RSM2257 设备地址 10001000.然后再发送数据。

   


使用特权

评论回复
地板
kxsi|  楼主 | 2019-7-25 11:07 | 只看该作者

数据

         RSM2257的数据是用来表示音量大小的。我们控制两个音频通道,以10dB为单位降低或增加音量。从功能设置位表格中可知数据为 11100B2B1B0.

        B2B1B0的数值决定了音量。请详见 衰减设置位。

   


使用特权

评论回复
5
kxsi|  楼主 | 2019-7-25 11:07 | 只看该作者

单片机I2C通信初始化设置

   1、设置端口为输入

              TRISC0 = input;
              TRISC1 = input;

    2、设置模式

           我们设置ssp1控制寄存器的 SSP1M<3:0>.我们需要的是I2C主模式。设置如下

           SSP1CON1bits.SSPM0 = 0;
           SSP1CON1bits.SSPM1 = 0;
           SSP1CON1bits.SSPM2 = 0;
           SSP1CON1bits.SSPM3 = 1;// I2C Master mode ,clock=Fosc/(4*(SSPxADD+1))

    3、设置时钟线频率RSM2257最大为100KHZ,我选择设置为50KHZ.

            使用计算公式clock=Fosc/(4*(SSPxADD+1)) 计算出SSP1ADD的值为0x9F;

             SSP1ADD=0x9F;

    4、开启I2C通信

           SSP1CON1bits.SSPEN = 1;


使用特权

评论回复
6
kxsi|  楼主 | 2019-7-25 11:08 | 只看该作者
单片机I2C发送程序

   1、发送起始位

    SSP1CON2bits.SEN = 1;//Start condition
    while(SSP1CON2bits.SEN == 1);//waiting for Start condition completed.

  2、发送地址
    PIR1bits.SSP1IF = 0;
    SSP1BUF = 0x88;//Device Address
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;
    // ~ACK  我们不理会接收方有没有应答。
  3、发送 10db音量控制的数据
    SSP1BUF = tx_data;//Data 10db level
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;
4、发送1db音量控制的数据
   //  ~ACK
    SSP1BUF = 0xD0;//Data 1db level
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;

  5,发送停止位
   //  ~ACK
    SSP1CON2bits.PEN = 1;//Stop condition

关于I2C通信协议,RSM2257,PIC MSSP 模块设置成I2C,更详细的内容就必须去看数据手册了。

使用特权

评论回复
7
kxsi|  楼主 | 2019-7-25 11:08 | 只看该作者
实例程序:程序分为main.c 和 define.h两个文件 芯片PIC16LF1823,开发环境MPLAB X IDE.

   define.h文件

/**********RA*********/
//B'1111,1000'H F8
#define LED_SW  RA5//IN
#define UP_SW   RA4//IN
#define DOWN_SW RA3//IN
#define LED     RA2//OUT
//RA1
//RA0
/**********RC***********/
//H FF
//RC0   SCL
//RC1   SDA
#define input 1
#define LED_VALUE  1
#define UP_VALUE   2
#define DOWN_VALUE 3
#define key_delay  300

使用特权

评论回复
8
kxsi|  楼主 | 2019-7-25 11:08 | 只看该作者
main.c文件

#include<pic.h>
#include"define.h"
__CONFIG(FOSC_INTOSC&WDTE_OFF&PWRTE_ON&MCLRE_OFF&CP_ON&CPD_OFF&BOREN_ON

                                                          &CLKOUTEN_OFF&IESO_ON&FCMEN_ON);
__CONFIG(PLLEN_OFF&LVP_OFF) ;
void tx_pro(unsigned char tx_db);
unsigned char DB_VALUE;
void init_fosc(void)
{
OSCCON = 0xF0;//32MHZ
}

使用特权

评论回复
9
kxsi|  楼主 | 2019-7-25 11:09 | 只看该作者
void init_gpio(void)
{
PORTA=0;
LATA =0;
ANSELA=0x00;
TRISA =0xF8;


PORTC=0;
LATC=0;
ANSELC = 0x00;
TRISC =0xFF;
}

使用特权

评论回复
10
kxsi|  楼主 | 2019-7-25 11:09 | 只看该作者
void init_i2c_master()
{
    TRISC0 = input;
    TRISC1 = input;
    SSP1CON1bits.SSPM0 = 0;
    SSP1CON1bits.SSPM1 = 0;
    SSP1CON1bits.SSPM2 = 0;
    SSP1CON1bits.SSPM3 = 1;// I2C Master mode ,clock=Fosc/(4*(SSPxADD+1))
    SSP1STATbits.SMP = 1;
    SSP1ADD = 0x9F;//SCL CLOCK Frequency 50KHZ
    SSP1CON1bits.SSPEN = 1;
}

使用特权

评论回复
11
kxsi|  楼主 | 2019-7-25 11:09 | 只看该作者
void i2c_master_tx(unsigned char tx_data)
{
    SSP1CON2bits.SEN = 1;//Start condition
    while(SSP1CON2bits.SEN == 1);//waiting for Start condition completed.


    PIR1bits.SSP1IF = 0;
    SSP1BUF = 0x88;//Device Address
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;
    // ~ACK
   
    SSP1BUF = tx_data;//Data 10db level
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;
   
   //  ~ACK
    SSP1BUF = 0xD0;//Data 1db level
    while(PIR1bits.SSP1IF == 0);
    PIR1bits.SSP1IF = 0;
   //  ~ACK
    SSP1CON2bits.PEN = 1;//Stop condition
}

使用特权

评论回复
12
kxsi|  楼主 | 2019-7-25 11:09 | 只看该作者
void delay(unsigned int n)
{
    while(n--);
}

使用特权

评论回复
13
kxsi|  楼主 | 2019-7-25 11:10 | 只看该作者
unsigned char key_board(void)
{
    if(LED_SW==1)
    {
        delay(key_delay);
        if(LED_SW==1)
        {
            while(LED_SW==1);
            return LED_VALUE;
        }
    }
    if(UP_SW==1)
    {
        delay(key_delay);
        if(UP_SW==1)
        {
            while(UP_SW==1);
            return UP_VALUE;
        }
    }
    if(DOWN_SW==1)
    {
        delay(key_delay);
         if(DOWN_SW==1)
        {
            while(DOWN_SW==1);
            return DOWN_VALUE;
        }


    }
    return 0;


}

使用特权

评论回复
14
kxsi|  楼主 | 2019-7-25 11:10 | 只看该作者
void DB_INC(void)
{
    if(DB_VALUE < 7)
    {
        DB_VALUE++;
        eeprom_write(0x00, DB_VALUE);//将音量值保存到EEPROM这样掉电后数据也不会丢失。
        tx_pro(DB_VALUE);
    }




}

使用特权

评论回复
15
kxsi|  楼主 | 2019-7-25 11:10 | 只看该作者
void DB_DEC(void)
{
    if(DB_VALUE  > 0)
    {
        DB_VALUE --;
        eeprom_write(0x00, DB_VALUE);
        tx_pro(DB_VALUE);
    }
}

使用特权

评论回复
16
kxsi|  楼主 | 2019-7-25 11:11 | 只看该作者
void tx_pro(unsigned char tx_db)
{
    tx_db |= 0xE0;           //将高三位设置为1。表示两个音频通道,以10dB为单位降低或增加音量
    i2c_master_tx(tx_db);//I2C发送数据程序
}

使用特权

评论回复
17
kxsi|  楼主 | 2019-7-25 11:11 | 只看该作者
int main(int argc, char** argv) {


    unsigned char keyvalue;
    init_fosc();
    init_gpio();
    init_i2c_master();
    LED=0;
    DB_VALUE= eeprom_read(0x00);//读eeprom 中保存的音量值
    if(DB_VALUE > 7)//如果之前没有设置过则音量不衰减
    {
      DB_VALUE = 0;
    }
    tx_pro(DB_VALUE);//用I2C通信设置RSM2257的音量
    while(1)
    {
         keyvalue=key_board();//判断按键程序,
         switch(keyvalue)
         {
             case LED_VALUE://LED按键按下
             {
                 LED = ~LED;
             };break;
             case UP_VALUE://音量加
             {
                 DB_INC();
                 
             };break;
             case DOWN_VALUE://音量减
             {
                 DB_DEC();
                 
             };break;
         }


    }


}

使用特权

评论回复
18
csyy| | 2019-7-25 18:37 | 只看该作者
你好,楼主,我按照你的方式配置,我使用的PIC16F18346配置的I2C主模式,仿真进去电平为什么没有变化呢?求指教

使用特权

评论回复
19
mintspring| | 2019-7-26 00:56 | 只看该作者
讲的很详细,非常好的。

使用特权

评论回复
20
奔波儿熊| | 2019-7-26 11:27 | 只看该作者
领导讲话, 这比喻666

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

3304

帖子

2

粉丝