#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(); }