前言
最近移植了FreeRTOS, 这里记录下FreeRTOS下温度传感器的简单驱动, 顺便试试看rom验证
硬件定义, 接口较为简单只需要一个GPIO, 根据硬件手册配置
//定义DS18B20引脚信息
#define DS18B20_PIN GPIO_Pin_11
//输入和输出的位带操作
#define DS18B20_DQ_OUT PGout(11)
#define DS18B20_DQ_IN PGin(11)
初始化逻辑
//定义GPIOG11为推挽输出
void DS18B20_IO_OUT(void) {
GPIO_InitTypeDef GPIO_Config;
GPIO_Config.GPIO_Pin = DS18B20_PIN;
GPIO_Config.GPIO_Mode = GPIO_Mode_Out_PP; //推挽
GPIO_Config.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOG, &GPIO_Config);
}
//定义GPIOG11为上拉输入
void DS18B20_IO_IN(void) {
GPIO_InitTypeDef GPIO_Config;
GPIO_Config.GPIO_Pin = DS18B20_PIN;
GPIO_Config.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOG, &GPIO_Config);
}
//使能 GPIOG 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
//默认推挽输出
DS18B20_IO_OUT();
读写入字节核心驱动
//读1字节数据函数
u8 DS18B20_Read_Byte(void) {
u8 i;
u8 data = 0;
for(i = 0; i < 8; i++) {
taskENTER_CRITICAL();
DS18B20_IO_OUT(); //配为输出
DS18B20_DQ_OUT = 0; //清零
delay_us(2);
DS18B20_IO_IN(); //配为输入
delay_us(8);
data |= DS18B20_DQ_IN << i; //从低位开始一位一位的获取保存到data中
delay_us(50); //延时等待传输下一个bit位
taskEXIT_CRITICAL();
}
return data;
}
//定义发送1字节函数, 1线总线数据传输, 注意时序要求较高容易被干扰
void DS18B20_Write_Byte(u8 data) {
u8 i;
DS18B20_IO_OUT(); //配置为输出准备开始发送数据
for(i = 0; i < 8; i++) {
taskENTER_CRITICAL(); //锁住 一线总线时序比较敏感需要加锁, 应尽快解锁
if(data & 0x01) { //写1操作
DS18B20_DQ_OUT = 0; //拉低
delay_us(2);
DS18B20_DQ_OUT = 1; //拉高
delay_us(60); //此时外设完成数据1的采样
} else { //写0操作
DS18B20_DQ_OUT = 0; //拉低
delay_us(60);
DS18B20_DQ_OUT = 1; //拉高,此时外设完成数据0的采样
delay_us(2);
}
taskEXIT_CRITICAL();//解锁
data >>= 1;
}
}
重置逻辑
//定义初始化复位函数,需参考时序图
u8 DS18B20_Reset(void) {
u8 retry = 0;
DS18B20_IO_OUT(); //先配置为输出
DS18B20_DQ_OUT = 0; //拉低电平
delay_us(500);
DS18B20_DQ_OUT = 1; //拉高电平
delay_us(30);
taskENTER_CRITICAL(); //临界区处理
//检测应答信号
DS18B20_IO_IN(); //配置为输入, 开始等待响应
while(DS18B20_DQ_IN && retry < 40) { // 先等待 低电平 最大40 微秒
retry++;
delay_us(1);
}
retry=0;
while(!DS18B20_DQ_IN && retry < 250) { //等待 高电平 最大 250 微秒
retry++;
delay_us(1);
}
taskEXIT_CRITICAL();
if(retry >= 240){ //根据白皮书不得超过240
printf("DS18B20 reset failed.\n");
return 0;
}
else {
return 1;
}
}
取得 rom 和检查
// crc8 计算
u8 CRC_CalcLowCrc8(u8 *pdat, u16 len)
{
unsigned char j;
unsigned char crc = 0x00;
while(len--)
{
crc ^= (*pdat++);
for (j=8; j>0; --j)
{
if (crc & 0x01)
crc = (crc >> 1) ^ 0x8C;
else
crc = (crc >> 1);
}
}
return crc;
}
// 取得 rom 然后检查crc
void DS18B20_GetRom(u8 rom[]) {
if (rom[8] == 0) {
s8 i = 0;
//复位
DS18B20_Reset();
//发送Read ROM命令
DS18B20_Write_Byte(0x33);
for(i = 0;i < 8 ;i++) {
rom[i] = DS18B20_Read_Byte();
}
print_log("Temp Rom Copy: length = 8");
print_mem(rom, 8);
print_info("CRC is %#x\r\n Start Test...", rom[7]);
if(rom[7] == CRC_CalcLowCrc8(rom, 7)) {
print_log("Matched");
rom[8] = 1; //标记已经初始化
}
print_log("");
}
}
最后取得温度
// 默认的rom
static u8 rom0[9];
//定义获取温度值的函数
float DS18B20_GetTemperature() {
u16 temp = 999; // 默认999
u16 temp_lsb = 0, temp_msb = 0; //暂存温度值的低字节和高字节
#ifdef USE_ROM
u8 i;
#endif
#ifdef USE_ROM
DS18B20_GetRom(rom0); //这里自动取得rom0, 也可以改为传其他rom
#endif
//复位
if(DS18B20_Reset()) {
#ifdef USE_ROM
DS18B20_Write_Byte(0x55);
for(i=0;i<8;i++){
DS18B20_Write_Byte(rom0[i]);
}
#else
DS18B20_Write_Byte(0xCC); //只有一个温度传感器, 则可以跳过rom检查
#endif
//发送温度转换命令,温度值保存到byte0和byte1内存中
DS18B20_Write_Byte(0x44);
//复位
if(DS18B20_Reset()) {
#ifdef USE_ROM
DS18B20_Write_Byte(0x55);
for(i=0;i<8;i++){
DS18B20_Write_Byte(rom0[i]);
}
#else
DS18B20_Write_Byte(0xCC);
#endif
//发送读内存命令
DS18B20_Write_Byte(0xBE);
//读取byte0和byte1
temp_lsb = DS18B20_Read_Byte();
temp_msb = DS18B20_Read_Byte();
// 合并得到温度的数字量
temp = (temp_msb << 8) | temp_lsb;
//负数转换
if((temp & 0xF800) == 0xF800) {
temp = ((~temp) + 1) * -1;
}
}
}
return temp * 0.0625; //最后乘以倍率
}