文章目录
- IIC总线篇
- 起始,终止信号
- 应答信号
- 发送,读取数据
- IIC通讯规则
- PCF8591-ADC-DAC篇
- 特性
- 一般说明
- 地址
- Control byte(控制字)
- 简单了解一下DAC电阻分隔链
- 应用为王
- DAC的应用
- 如何设置DAC输出
- 如何调用DAC功能
- ADC的应用
- ADC采集特点
- ADC读模式
- 如何设置ADC采集
- 如何调用ADC功能
- ADC现象演示
- DAC现象演示
IIC总线篇
IIC底层驱动资源包
起始,终止信号
说人话:在SCL保持高电平的时候。SDA从高电平跳变到低电平就是起始信号,从低电平跳变到高电平
void IIC_Start()
{
sda = 1;
scl = 1;
_nop_();
sda = 0;
_nop_();
}
void IIC_Stop()
{
sda = 0;
scl = 1;
_nop_();
sda = 1;
_nop_();
}
应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
char IIC_ACK()
{
char flag;
sda = 1;//在时钟脉冲9期间 释放数据线
_nop_();
scl = 1;
_nop_();
flag = sda;
_nop_();
scl = 0;
_nop_();
return flag;
}
发送,读取数据
说人话:在SCL为高电平期间数据不可以变化,在SCL为低电平期间数据才可以变化
发送时序:
void IIC_Send_Byte(char dataSend)
{
int i;
for(i = 0;i<8;i++){
scl = 0;//scl拉低,让sda做好数据准备
sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
_nop_();//发送数据建立时间
scl = 1;//scl拉高开始发送
_nop_();//数据发送时间
scl = 0;//发送完毕拉低
_nop_();//
dataSend = dataSend << 1;
}
}
读取数据
unsigned char IIC_Read_Byte(char dataRead)
{
unsigned char dataRead;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;//scl拉高,准备去读数据
_nop_();//读取时间
dataRead <<= 1;//读取进来数据
if(dataRead) //判断读的是1吗?
dataRead |= 0x01;
scl = 0; //读取完毕 拉低
_nop_();
}
return dataRead;
}
IIC通讯规则
在写模式下,通过发送,下一个数据传输的停止条件或开始条件来终止数据传输。
我的理解是:在写完地址,和控制字以后,不必IIC_Stop,可以直接IIC_Start,写其他的指令
PCF8591-ADC-DAC篇
以下内容全部来自芯片数据手册节选 以及 个人理解总结
特性
重点黄色
说人话:
1.通过I2C总线串行输入/输出
2.地址由3个硬件地址引脚组成
3.采样速率取决于I2C 总线速度
4.4 个模拟输入可编程为单端或差分输入
5.自动增量通道选择
6.模拟电压范围:VSS~VDD
一般说明
说人话:
1.地址引脚A0、A1和A2
2.允许使用最多8个连接到i2c总线的设备,
3.通过两行双向I2c总线串行传输。
4.该设备的功能包括模拟输入多路复用、片上跟踪和保持功能、8位模数转换和8位数模转换。
地址
结合CT107D原理图:
地址 写指令:0x90,读指令:0x91;
地址部分说明:
说人话:
1.IIC主设备,通过IIC总线必须发送一个有效的地址来激活设备;
2.有效的地址由固定和可编程部分组成;
3.可编程部分必须根据地址引脚A0,A1,A2进行设置;
4.地址指令,必须是启动条件后的第一个字节进行发送;
5。地址指令的最后一位也就是(R/W)设置数据传输的方向是读还是写;
Control byte(控制字)
说人话:
第6位:是否使能DAC,1-开启DAC输出功能 0-不开启
第5,4位:选择ADC输入采取什么样的方式,默认四个单端输入(00)
第3位:ADC通道是否要开启自动增加 1-自动增加 0-不自动增加
第2,1位:选择采集的ADC通道
简单了解一下DAC电阻分隔链
说人话:通过控制寄存器D7-D0位 进而 控制256个选择开关,达到控制电阻分压,进而输出对应的电压
比如: D7-D1全赋值 1,则就输出5v电压;全赋0,就是输出0v
对应关系就是:0v-5v 对应 0x00-0xff
应用为王
DAC的应用
本身就是一路写到底模式,不必要注意IIC通讯规则
如何设置DAC输出
void DacOut(u8 val)
{
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x40);
I2CWaitAck();
I2CSendByte(val);
I2CWaitAck();
I2CStop();
}
如何调用DAC功能
u8 dac_cnt =0 ;
void DacTask()
{
if(dac_cnt>=102){
dac_cnt =0 ;
DacOut(51*3);
}
}
ADC的应用
ADC采集特点
说人话:就是开启一次读指令,A/D就一直开始周期性转换了
ADC读模式
要结合博文开头的IIC通讯规则
因为要先写地址,再写控制字,再写地址)
(顺序就是 ADDRESS(写)->contrl word->ADDRESS(读))
个人理解:前面介绍到iic_start后面必须写ADDRESS指令,而我发完control word 必须要再次启动iic_start,才能去写ADDRESS(读),又因为本身就在写模式,再写完control word 不需要iic_stop,直接iic_start即可
注意这里写通道的时候写0x4~(为了和DAC功能同时作用)
步骤:启动->地址(写指令的)->WaitACK->控制字(包含选哪个通道)->WaitAck->再次启动->地址(读指令的)->WaitAck->读数值->发送应答->停止总线
这里测的是电位器通道是0x43,光敏是0x41(为了同时开启ADC和DAC功能,默认使能dac)
如何设置ADC采集
u8 ReadAdc(u8 ch)
{
u8 tmp ;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(ch);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
tmp = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return tmp;
}
如何调用ADC功能
连续读取多通道的细节问题(数据实时性问题)
PCF8591
每读出一次,它启动一次转换
转换的结果,在下次,才能读出
所以连续读俩次,第一次空读,数据扔掉
u8 adc_cnt =0 ;
u8 adc_val = 0;
u16 adc_dis = 0;//volt 扩大了 100
u16 adc_dis1 = 0;//lighting
void AdcTask()
{
if(adc_cnt>=101){
adc_cnt = 0;
ReadAdc(0x43); //iic总线上读取的数据,是adc
adc_dis = (u16)(ReadAdc(0x43)*100.f/51);//(寄存器数值)*100.f/51 = x.xx xxx
ReadAdc(0x41);
adc_dis1 = ReadAdc(0x41);
}
}
ADC现象演示
(十)IIC总线-PCF8591-ADC/DAC
DAC现象演示
自行用电压表测量
----- 如有错误欢迎大家批评指正!!!