传感器模块总结
1、PCF8591
通讯方式:IIC
寄存器
最高位(第七位):固定为0
第六位:DAC功能使能
第五,四位:通道读取方式选择
第三位:默认为0
第二位:自动增量模式使能
第一,零位:通道选择
通讯步鄹:
见代码注释
通讯时易错点:
①、ADC时每次读取完数据就发送非应答位。
②、弱需要DAC功能,不论ADC模式下还是DAC模式下发送功能数据时,控制位第6位必须置1!
③、中断对其无影响。
④、PCF8591转换始终位八个SCL周期,即IIC传送一个字节的时间,因此需要先将PCF8591读取一个空字节,第二次读取的数值才为真实数值。
驱动代码
//IIC读取八位ad转换数值
uint8 IIC_GetVal()
{
uint8 Val;
IIC_Start(); //IIC启动
IIC_SendByte(0x90); //IIC选择地址,并发送写指令
IIC_WaitAck(); //等待IIC应答
IIC_SendByte(0x43); //选择模拟量输入通道
IIC_WaitAck();
IIC_Stop(); //IIC停止,接下来开始读取数据
IIC_Start(); //IIC启动
IIC_SendByte(0x91); //IIC选择地址,并发送读指令
IIC_WaitAck(); //IIC等待应答
IIC_RecByte(); //接收PCF8591空字节
IIC_SendAck(0); //发送应答位
Val = IIC_RecByte(); //接收PCF8591数据
IIC_SendAck(1); //发送非应答位
IIC_Stop();
return Val;
}
uint8 IIC_GetLit()
{
uint8 Val;
IIC_Start(); //IIC启动
IIC_SendByte(0x90); //IIC选择地址,并发送写指令
IIC_WaitAck(); //等待IIC应答
IIC_SendByte(0x41); //选择模拟量输入通道
IIC_WaitAck();
IIC_Stop(); //IIC停止,接下来开始读取数据
IIC_Start(); //IIC启动
IIC_SendByte(0x91); //IIC选择地址,并发送读指令
IIC_WaitAck(); //IIC等待应答
IIC_RecByte(); //接收PCF8591空字节
IIC_SendAck(0); //发送应答位
Val = IIC_RecByte(); //接收PCF8591数据
IIC_SendAck(1); //发送非应答位
IIC_Stop();
return Val;
}
void DAC(uint8 a_Data)
{
a_Data = a_Data*(256/5);
IIC_Start(); //IIC启动
IIC_SendByte(0x90); //IIC选择地址,并发送写指令
IIC_WaitAck(); //等待IIC应答
IIC_SendByte(0x43); //选择模拟量输入通道
IIC_WaitAck();
IIC_SendByte(a_Data); //IIC选择地址,并发送读指令
IIC_WaitAck(); //IIC等待应答
IIC_Stop();
}
2、EEPROM
通讯方式:IIC
通讯步鄹:
见代码
通讯易错点:
①视情况需要关闭中断
②连续读数据时,在读最后一位之前回应的应答位都为ACK(0)来表示可以继续读数据(用NACK(1)应答会导致无法读出下一个数据)。
③当数据读入最后一位时,用NACK(1)来应答(实际上用ACK(0)应答也可以,但是用NACK(1)更规范)
④初始化有两种方法,一是根据要存入的数据范围判断是否存入,二是可以设置多余的标志位。
⑤每次写数据之间需要有间隔,若用按键改变数据的值化,可把写数据的操作放在按键中。
代码
void EEPROM_Write(uint8 addr,uint8 dat)
{
EA = 0;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
EA = 1;
}
uint8 EEPROM_Read(uint8 addr, bit ack)
{
uint8 Val;
EA = 0;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
Val = IIC_RecByte();
IIC_Ack(ack);
IIC_Stop();
EA = 1;
return Val;
}
EEPROM初始化
方法一:
void Init_EEPROM()
{
if(EEPROM_Read(0x38,0)==0x38)//当标志位存在
{
此处根据需要读取EEPROM的存储的值
当读取最后一个字节时应答位为NACK(1)
}
else //当标志位不存在
EEPROM_Write(0x38,0x38);
}
方法二
void Init_EEPROM()
{
uint8 x = 0xff;
x = EEPROM_Read(addr,0);
if(x > n1 && x < n2) //(n1,n2)为所存储数值的范围
{
此处根据需要读取EEPROM的存储的值
当读取最后一个字节时应答位为NACK(1)
}
else //当读取数值不在此范围
EEPROM_Write(0x38,0x38);
}
3、DS18B20
通讯方式:
onewire单总线传输
配置寄存器
通讯步鄹:
- 初始化DS18B20
- 写入0xcc指令,跳过rom操作
- 写入0x44指令,开始温度转换
- 延迟大概700ms,等待温度转换
- 写入0xcc指令,跳过rom操作
- 写入0xbe指令,开始读取温度
- 读取高八位
- 读取低八位
- 高低八位数据合并转换计算
通讯易错点
①onewire单总线传输无时钟线,对时序要求高,因此需要关闭中断。
②延迟700ms读取温度器件可以不关闭中断,此时可以执行普通工作。
③整理后的16位数据,前四位为符号,中间八位为整数,后四位为小数。
代码
uint16 rd_temperature()
{
uint8 LSB,MSB;
uint16 temp_Val;
/********发送指令********/
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
/********延迟********/
Delay_OneWire(100);
/********发送指令********/
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
/********读取数据********/
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
/********温度数据转换********/
temp_Val = MSB;
temp_Val = (temp_Val<<8)|LSB;
temp_Val = temp_Val>>4;
return temp_Val;//此处温度被转换成整数
}
4、DS1302
通讯方式:
类SPI通讯
寄存器
秒寄存器的CH位为时钟停止标志位,置1开启,置0关闭。
第八个寄存器的WP位为写保护位,置1开启,置0关闭。
通讯步鄹:
见代码
通讯细节与易错点
①需要写入DS1302的数值时,应该WP位置1,启动时置0。
②设置DS1302时,可CH位置1,停止时钟震动,设置完毕在开启。
③设置时关闭循环中对DS1302数值的读取,防止设置的数被读取函数改变。
④SPI通讯有时钟线,因此可以不关闭中断。
代码
unsigned char Write_DS1302_adrr[7] =
{0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8E};
unsigned char Read_DS1302_adrr[7] =
{0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char Timer[7];
void DS1302_Config()
{
unsigned char i;
Write_Ds1302_Byte( 0x8e, 0x00);
for(i = 0; i < 7; i++)
{
Write_Ds1302_Byte( Write_DS1302_adrr[i], Timer[i]);
}
Write_Ds1302_Byte( 0x8e, 0x80);
}
void Read_DS1302_Timer()
{
unsigned char i;
for(i = 0; i < 7; i++)
{
Timer[i] = Read_Ds1302_Byte( Read_DS1302_adrr[i] );
}
}
后记
由于一些事情,咕了许久,第九届之后的赛题写了懒得更新 ,这些传感器整会了,赛题就轻松多了。