IIC底层驱动程序
这次I是普通I/O端口模拟IIC通信实验
具体引脚配置如下:
IIC主控实验----底层驱动GPIO配置
GPIO初始化配置
具体代码如下:
- //初始化IIC
- void IIC_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 输出高电平---空闲状态
- }
复制代码
时钟线(SCL)—GPIO功能配置
在IIC通信中,主控的时钟线(SCL) 一直是输出状态
具体程序如下:
- //时钟线(SCL):PB6输出---高电平
- #define SCL_H GPIO_SetBits(GPIOB,GPIO_Pin_6)
- //时钟线(SCL):PB6输出---低电平
- #define SCL_L GPIO_ResetBits(GPIOB,GPIO_Pin_6)
复制代码
数据线(SDA)—GPIO功能配置
由于IIC通信是半双工通信方式
因而数据线(SDA)可能会是数据输入,也可能是数据输出。
- 数据线(SDA)输入模式
- //数据线(SDA):PB7输入
- #define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
- //读取PB7的电平
- #define READ_SDA GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
复制代码
数据线(SDA)输出模式
- //数据线(SDA):PB7输出
- #define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
- //数据线(SDA):PB7输出---高电平
- #define SDA_H GPIO_SetBits(GPIOB,GPIO_Pin_7)
- //数据线(SDA):PB7输出---低电平
- #define SDA_L GPIO_ResetBits(GPIOB,GPIO_Pin_7)
复制代码
IIC主控实验----底层驱动程序
开始信号
当时钟线SCL 为高电平时,数据线SDA 由高电平向低电平跳变。
具体程序如下:
- void IIC_Start(void)//开始信号
- {
- SDA_OUT(); //数据线(SDA)输出模式
- SDA_H; //数据线(SDA)输出高电平
- SCL_H; //时钟线(SCL)输出高电平
- delay_us(5);
- SDA_L; //数据线(SDA)输出低电平
- delay_us(5);
- SCL_L; //时钟线(SCL)输出低电平
- }
复制代码
终止信号
当时钟线SCL 为高电平时,数据线SDA 由低电平向高电平跳变。
具体程序如下:
- void IIC_Stop(void)//终止信号
- {
- SDA_OUT(); //数据线(SDA)输出模式
- SCL_L; //时钟线(SCL)输出低电平
- SDA_L; //数据线(SDA)输出低电平
- delay_us(5);
- SCL_H; //时钟线(SCL)输出高电平
- SDA_H; //数据线(SDA)输出高电平
- delay_us(5);
- }
复制代码
应答信号
我们这里写的是IIC主控程序,在读取从控数据的时候,需要回复应答信号。
产生应答信号,表示接收数据成功。
具体程序如下:
- void IIC_Ack(void)//产生应答信号
- {
- SCL_L; //时钟线(SCL)输出低电平
- SDA_OUT(); //数据线(SDA)输出模式
- SDA_L; //数据线(SDA)输出低电平
- delay_us(2);
- SCL_H; //时钟线(SCL)输出高电平
- delay_us(5);
- SCL_L; //时钟线(SCL)输出低电平
- }
复制代码
产生非应答信号,表示接收数据失败。
具体程序如下:
- void IIC_NAck(void)//不产生应答信号
- {
- SCL_L; //时钟线(SCL)输出低电平
- SDA_OUT(); //数据线(SDA)输出模式
- SDA_H; //数据线(SDA)输出高电平
- delay_us(2);
- SCL_H; //时钟线(SCL)输出高电平
- delay_us(5);
- SCL_L; //时钟线(SCL)输出低电平
- }
复制代码
IIC主控程序,在写入数据到从控的时候,需要等待应答信号。
- //返回值:1,接收应答失败
- // 0,接收应答成功
- u8 IIC_Wait_Ack(void)//等待应答信号
- {
- int uc=0;
- SDA_IN(); //数据线(SDA)输入模式
- SDA_H; delay_us(1);
- SCL_H; delay_us(1);
- while(READ_SDA)
- {
- uc++;
- if(uc>250)//接收应答失败
- {
- IIC_Stop();//发送终止信号
- return 1;
- }
- }
- SCL_L;
- return 0;
- }
复制代码
数据传输
IIC总线进行数据传送时,时钟线(SCL)上的信号为高电平期间,数据线(SDA)上的数据必须保持稳定。
只有在时钟线(SCL)上的信号为低电平期间,数据线(SCL)上的高电平或低电平状态才允许变化。
输出到数据线(SDA)上的每个字节必须是8位
数据传送时,先传送最高位(MSB),后传送最低位(LSB)
每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)
IIC主控发送一个字节数据
具体程序如下:
- void IIC_Send_Byte(u8 txdata)//发送一个字节数据---高位在前,低位在后
- {
- SDA_OUT(); //数据线(SDA)输出模式
- SCL_L;
- for(int t=0;t<8;t++) //高位在前,低位在后。
- {
- if((txdata&0x80)>>7) SDA_H;
- else SDA_L;
- txdata<<=1;
- delay_us(2);
- SCL_H;
- delay_us(2);
- SCL_L;
- delay_us(2);
- }
- }
复制代码
IIC主控接收一个字节数据
具体程序如下:
- u8 IIC_Read_Byte(unsigned char ack)//读取一个字节数据---ack=1时,发送ACK,ack=0,发送nACK
- {
- unsigned char rxdata=0,i;
- SDA_IN(); //数据线(SDA)输入模式
- for(i=0;i<8;i++)
- {
- SCL_L;
- delay_us(2);
- SCL_H;
- rxdata<<=1;
- if(READ_SDA) rxdata++;
- delay_us(1);
- }
- if(!ack) IIC_NAck();
- else IIC_Ack();
- return rxdata;
- }
复制代码
————————————————
版权声明:根号五
|