232 lines
6.1 KiB
C
232 lines
6.1 KiB
C
#include "m1820.h"
|
||
#include "main.h"
|
||
#include "delay.h"
|
||
|
||
#define IO_H HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_SET) //PC10 Tx
|
||
#define IO_L HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_RESET) //PC10 Tx
|
||
|
||
#define IO_R HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_11) //PC11 Rx
|
||
|
||
|
||
|
||
void M1820_GPIO_Init(void)
|
||
{
|
||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||
|
||
/* GPIO Ports Clock Enable */
|
||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||
|
||
GPIO_InitStruct.Pin = GPIO_PIN_11;
|
||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //PC11 Rx
|
||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||
|
||
GPIO_InitStruct.Pin = GPIO_PIN_10;
|
||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //PC10 Tx
|
||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||
|
||
}
|
||
|
||
|
||
//单片机只需要用一个普通的IO口和M1820的DQ引脚相连,然后控制这个IO口输出高低电平即可
|
||
|
||
//复位M1820
|
||
//作用:复位
|
||
void M1820_Rst(void)
|
||
{
|
||
// M1820_IO_OUT(); //把单片机的IO口配置为输出
|
||
IO_L; //拉低DQ
|
||
delay_us(750); //拉低750us,这个时间是根据M1820本身的规则定的,数据手册中480-960us
|
||
IO_H; //拉高DQ
|
||
delay_us(15); //15US
|
||
}
|
||
|
||
//等待M1820的回应
|
||
//作用:检查单片机和M1820的通讯是否正常
|
||
//返回1:未检测到M1820的存在(可能是DQ引脚没有上拉电阻,通讯的时序不对,芯片损坏等原因)
|
||
//返回0:存在
|
||
uint8_t M1820_Check(void)
|
||
{
|
||
uint8_t retry=0;
|
||
// DS18B20_IO_IN();//SET PA0 INPUT
|
||
while ((IO_R == 1) && retry<200)
|
||
{
|
||
retry++;
|
||
delay_us(1);
|
||
};
|
||
if(retry>=200)return 1;
|
||
else retry=0;
|
||
while ((IO_R == 0) && retry<240)
|
||
{
|
||
retry++;
|
||
delay_us(1);
|
||
};
|
||
if(retry>=240)return 1;
|
||
return 0;
|
||
}
|
||
//从M1820读取一个位
|
||
//作用:读取一个位数据,重复调用该函数可以把温湿度数据读出来
|
||
//返回值:1/0
|
||
uint8_t M1820_Read_Bit(void) // read one bit
|
||
{
|
||
uint8_t data;
|
||
// M1820_IO_OUT(); //单片机输出一个由低到高的上升沿脉冲给M1820
|
||
IO_L;
|
||
delay_us(2);
|
||
IO_H;
|
||
// M1820_IO_IN(); //把IO口配置为输入,读取电平
|
||
delay_us(12);
|
||
if(IO_R)
|
||
{ //如果是高电平,则M1820输出的数据是'1',否则为'0'
|
||
data = 1;
|
||
}
|
||
else
|
||
{
|
||
data = 0;
|
||
}
|
||
delay_us(50); //所有读时隙至少持续60us
|
||
return data;
|
||
}
|
||
|
||
//从M1820读取一个字节
|
||
//作用:连续读8个位,并合成一个字节数据
|
||
//返回值:读到的数据
|
||
uint8_t M1820_Read_Byte(void) // read one byte
|
||
{
|
||
uint8_t i,j,dat;
|
||
dat = 0;
|
||
for (i = 1;i <= 8;i++)
|
||
{
|
||
j = M1820_Read_Bit(); //连续调用8次
|
||
dat = (j << 7) | (dat >> 1);//先把之前的数据右移1位,再把新读的数据置于最高位,8次循环组成一个字节
|
||
}
|
||
return dat; //返回合成的1字节数据
|
||
}
|
||
|
||
|
||
//写一个字节到M1820
|
||
//作用:写数据到M1820,调用这个函数可以发送指令控制M1820
|
||
//dat:要写入的字节
|
||
void M1820_Write_Byte(uint8_t dat)//数据传输必须先低后高
|
||
{
|
||
uint8_t j;
|
||
uint8_t testb;
|
||
// M1820_IO_OUT();//SET PA0 OUTPUT;
|
||
for (j = 1;j <= 8;j++)
|
||
{
|
||
testb = dat & 0x01; //把传进来的这个数据的最低位提取出来
|
||
dat = dat >> 1; //dat的数据右边移1位,作用是把次高位移到最高位,被移除的1位在上一行被testb记录
|
||
if (testb) //如果最低位数据为'1'
|
||
{
|
||
IO_L; // Write 1
|
||
delay_us(2); //两个写时隙时间恢复时间至少1us
|
||
IO_H; //输出60us高电平,相当于告诉M1820要传的数据是'1'
|
||
delay_us(60); //所有写时隙至少持续60us
|
||
}
|
||
else //如果最低位数据为'0'
|
||
{
|
||
IO_L; //输出60us低电平,相当于告诉M1820要传的数据是'0'
|
||
delay_us(60); //所有写时隙至少持续60us
|
||
IO_H;
|
||
delay_us(2); //两个写时隙时间恢复时间至少1us
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//开始温度转换
|
||
//作用:从M1820中读取温度数据
|
||
void M1820_Start(void) // ds1820 start convert
|
||
{
|
||
M1820_Rst(); //复位
|
||
M1820_Check(); //检查单片机和M1820的通讯是否正常
|
||
M1820_Write_Byte(0xcc); //寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
|
||
M1820_Write_Byte(0x44); //0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
|
||
}
|
||
|
||
|
||
//初始化M1820的IO口DQ 同时检测M1820的存在
|
||
//返回1:不存在
|
||
//返回0:存在
|
||
|
||
uint8_t M1820_Init(void)
|
||
{
|
||
// GPIO_InitTypeDef GPIO_InitStructure;
|
||
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA口时钟
|
||
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽输出
|
||
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||
// GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||
|
||
// GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出1
|
||
|
||
M1820_GPIO_Init(); //端口初始化
|
||
|
||
IO_H; //输出 1
|
||
|
||
M1820_Rst(); //复位
|
||
|
||
return M1820_Check();
|
||
}
|
||
|
||
//从M1820得到温度值
|
||
//精度:0.1C
|
||
//返回值:温度值 (-550~1250)
|
||
float M1820_Get_Temp(void)
|
||
{
|
||
uint8_t t_sign = 0;
|
||
uint8_t TL = 0,TH = 0;
|
||
short temp = 0;
|
||
|
||
M1820_Start (); //开始采集温度
|
||
M1820_Rst(); //复位
|
||
M1820_Check(); //检查单片机和M1820通讯是否正常
|
||
M1820_Write_Byte(0xcc); //寻址总线上的所有从设备,详细说明可以参考数据手册ROM COMMANDS
|
||
M1820_Write_Byte(0xbe); //0x44命令为启动温度转换命令,详细说明可以参考数据手册ROM COMMANDS
|
||
|
||
//数据由两个字节组成,低位对应2^(-8)-2^(-1),高位对应2^(0)-2^(6)+最高位符号位,分辨率为2^(-8)即1/256
|
||
TL = M1820_Read_Byte(); //读取数据低字节
|
||
TH = M1820_Read_Byte(); //读取数据高字节
|
||
|
||
if(TH > 7) //0x7F->01111111,大于0x7F意味着最高位为1,表示负数
|
||
{
|
||
t_sign = 0; //温度为负
|
||
}
|
||
else
|
||
{
|
||
t_sign = 1; //温度为正
|
||
}
|
||
temp = TH; //获得高字节数据
|
||
temp <<= 8; //高字节位左移8位
|
||
temp += TL; //左移的高8位加上低8位合成一个16位数据
|
||
// tem = (float)tem/256+40; //M1820Z手册: 摄氏度 = ST/256 + 40,低8位对应2^(-8)-2^(-1),高8位对应2^(0)-2^(6)+最高位符号位
|
||
float result = 0;
|
||
if(t_sign)
|
||
{
|
||
result = (float)temp*0.0625;
|
||
return result; //返回温度值
|
||
}
|
||
else
|
||
{
|
||
temp = ~temp; //取反
|
||
result = - (float)temp*0.0625;
|
||
return result;
|
||
}
|
||
}
|
||
|
||
|
||
////执行
|
||
//float TEMP = 0;
|
||
//void M1820_Act(void)
|
||
//{
|
||
//// M1820_Init();
|
||
// TEMP = M1820_Get_Temp();
|
||
//}
|
||
|
||
|
||
|
||
|