一.看图模拟IIC
1.宏定义io和初始化io
#define IIC_SCL_PORT GPIOC
#define IIC_SCL_PIN GPIO_Pin_3
#define IIC_SCL_L GPIO_ResetBits(IIC_SCL_PORT, IIC_SCL_PIN)
#define IIC_SCL_H GPIO_SetBits(IIC_SCL_PORT, IIC_SCL_PIN)
#define IIC_SDA_PORT GPIOC
#define IIC_SDA_PIN GPIO_Pin_2
#define IIC_READ_SDA GPIO_ReadInputDataBit(IIC_SDA_PORT,IIC_SDA_PIN)
#define IIC_SDA_L GPIO_ResetBits(IIC_SDA_PORT, IIC_SDA_PIN)
#define IIC_SDA_H GPIO_SetBits(IIC_SDA_PORT, IIC_SDA_PIN)
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_sda_out
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 输出模式
**
**--------------------------------------------------------------------------------------------------------**/
void iic_sda_out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_sda_in
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 输入模式
**
**--------------------------------------------------------------------------------------------------------**/
void iic_sda_in(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_init
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 初始化IO口
**
**--------------------------------------------------------------------------------------------------------**/
void iic_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD
| RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = IIC_SCL_PIN;
GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
IIC_SCL_H;
GPIO_InitStructure.GPIO_Pin = IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
IIC_SDA_H;
}
2.模拟:启动信号 停止信号
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
![在这里插入图片描述](https://img-blog.csdnimg.cn/a0c4631f8dc94d76b43cd4274bc4ba52.png
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_start
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
**
**--------------------------------------------------------------------------------------------------------**/
void iic_start(void)
{
iic_sda_out();//sda线输出
IIC_SDA_H;
IIC_SCL_H;
delay_us(10);
IIC_SDA_L;//start:when CLK is high,DATA change form high to low
delay_us(10);
IIC_SCL_L;//钳住I2C总线,准备发送或接收数据
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_stop
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
**
**--------------------------------------------------------------------------------------------------------**/
void iic_stop(void)
{
iic_sda_out();//sda线输出
IIC_SCL_L;
IIC_SDA_L;//stop:when SCL is high,DATA change form low to high
delay_us(10);
IIC_SCL_H;/*end */
delay_us(2);
IIC_SDA_H;
delay_us(10);
}
3.模拟:应答信号 、非应答信号、等待应答信号
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。(大白话理解应答:A向B读取数据,A是接收数据者,B是发送数据者。A接收完一个8位数据后,要发送一个信号告诉B让它结束发送。该信号分高电平和低电平,A是发送应答,B是等待应答)
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_ack
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 产生ACK应答 SDA是低电平
**
**--------------------------------------------------------------------------------------------------------**/
void iic_ack(void)
{
IIC_SCL_L;
iic_sda_out();
IIC_SDA_L;
delay_us(10);
IIC_SCL_H;
delay_us(10);
IIC_SCL_L;
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_nack
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 不产生ACK应答 SDA是高电平
**
**--------------------------------------------------------------------------------------------------------**/
void iic_nack(void)
{
IIC_SCL_L;
iic_sda_out();
IIC_SDA_H;
delay_us(10);
IIC_SCL_H;
delay_us(10);
IIC_SCL_L;
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_wait_ack
**@author:
**@data:
**@param:void
**@param:void
**@return:void 1,接收应答失败 0,接收应答成功
**@descriptions: 等待应答信号到来
**
**--------------------------------------------------------------------------------------------------------**/
u8 iic_wait_ack(void)
{
u8 wait_time=0;
IIC_SDA_H;/*释放控制权,进入空闲等待让对方发送应答信号*/
delay_us(6);
IIC_SCL_H;/*释放控制权,进入空闲等待让对方发送应答信号*/
delay_us(6);
iic_sda_in(); //SDA设置为输入
while(IIC_READ_SDA)
{
wait_time++;
if(wait_time>250)
{
iic_stop();
return 1;/*未等接收到应答信号,发送数据失败*/
}
}
IIC_SCL_L;
return 0;
}
4.模拟:发送数据、接收数据
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_send_byte
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: IIC发送书1个字节
**
**--------------------------------------------------------------------------------------------------------**/
void iic_send_byte(u8 data)
{
u8 pnext;
iic_sda_out();
IIC_SCL_L;/*SCL ENABLE*/
for(pnext=0;pnext<8;pnext++)
{
/*send direction high_8 to low_8, ready data*/
if((data&0x80)>>7){IIC_SDA_H;}
else{IIC_SDA_L;}
data<<=1;
delay_us(10); /*SCL is high ,start send data*/
IIC_SCL_H;
delay_us(10);
IIC_SCL_L; /*send data end,enable SCL*/
delay_us(10);
}
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: iic_read_byte
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: IIC读取数据1个字节,ack=1时,发送ACK,ack=0,发送nACK
**
**--------------------------------------------------------------------------------------------------------**/
u8 iic_read_byte(u8 ack)
{
u8 pnext,receive=0;
iic_sda_in();//SDA设置为输入
for(pnext=0;pnext<8;pnext++ )
{
IIC_SCL_L;
delay_us(10);
IIC_SCL_H;/*SCL is high ,start read data */
receive<<=1;
if(IIC_READ_SDA)receive++;
delay_us(5);
}
if (!ack)
iic_nack();//发送nACK
else
iic_ack(); //发送ACK
return receive;
}
二KS103探测距离
1.官网手册地址如下:http://www.dauxi.com/KS10X-V110_CN.pdf
2.读取探测结果和开始探测
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: ks103_readonebyte
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 读取ks103探测结果
**
**--------------------------------------------------------------------------------------------------------**/
u8 ks103_readonebyte(u8 addr, u8 reg)
{
u8 result=0;
iic_start();
iic_send_byte(addr);
iic_wait_ack();
iic_send_byte(reg);
iic_wait_ack();
iic_start();
iic_send_byte(addr+ 1);
iic_wait_ack();
delay_us(50);
result=iic_read_byte(0);
iic_stop();
return result;
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: ks103_writeonebyte
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 开始ks103探测
**
**--------------------------------------------------------------------------------------------------------**/
void ks103_writeonebyte(u8 addr,u8 reg,u8 cmd)
{
iic_start();
iic_send_byte(addr);
iic_wait_ack();
iic_send_byte(reg);
iic_wait_ack();
iic_send_byte(cmd);
iic_wait_ack();
iic_stop();
}
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: ks103_change_addr
**@author:
**@data:
**@param:void :source 当前的ks103地址
**@param:void :destin 新地址
**@return:void
**@descriptions: ks103修改地址 default :0xe8
**
**--------------------------------------------------------------------------------------------------------**/
void ks103_change_addr(u8 source, u8 destin)
{
ks103_writeonebyte(source,0x02,0x9a);
delay_ms(5);
ks103_writeonebyte(source,0x02,0x92);
delay_ms(5);
ks103_writeonebyte(source,0x02,0x9e);
delay_ms(5);
ks103_writeonebyte(source,0x02,destin);
delay_ms(500);
}
u16 result_distance=0;/*mm*/
u8 distance_h=0;
u8 distance_l=0;
/**--------------functiion Info---------------------------------------------------------------------------------
**@functiion name: main
**@author:
**@data:
**@param:void
**@param:void
**@return:void
**@descriptions: 主函数
**
**--------------------------------------------------------------------------------------------------------**/
void main(void)
{
iic_init();
while(1)
{
ks103_writeonebyte(0xE8,0x02,0xb0);/*开始探测 0xe8是超声波地址,0xb0探测指令返回mm*/
delay_ms(50);
distance_h = ks103_readonebyte(0xE8, 0x02);/*读取探测结果 0xe8是超声波地址,返回mm*/
distance_l= ks103_readonebyte(0xE8, 0x03);/*读取探测结果 0xe8是超声波地址,返回mm*/
result_distance=distance_h<<8 |distance_l;
delay_ms(50);
}
}