小熊派GD32开发(7) 您所在的位置:网站首页 iic软件模拟代码 小熊派GD32开发(7)

小熊派GD32开发(7)

2024-01-04 13:28| 来源: 网络整理| 查看: 265

小熊派GD32开发(7)— 使用软件模拟I2C读取SHT30温湿度传感器 一、编写软件模拟I2C驱动程序

在【Devices】下新建soft_i2c.c和soft_i2c.h文件,首先,查看硬件原理图,可以看到,IIC_SCL使用PB6引脚,IIC_SDA使用PB7引脚,将这两个引脚初始化即可:

/* 软件模拟IIC引脚初始化 * IIC_SCL --> PB6 * IIC_SDA --> PB7 */ void IIC_Init(void) { rcu_periph_clock_enable(RCU_GPIOB); /* 使能GPIOB时钟 */ /* 配置IIC_SCL引脚为推挽输出 */ gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); /* 配置IIC_SDA引脚为推挽输出 */ gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7); gpio_bit_set(GPIOB, GPIO_PIN_6); gpio_bit_set(GPIOB, GPIO_PIN_7); }

因为模拟IIC通信里需要用到us延时,所以,编写一个us延时函数

/* 描述:us级延时函数 * 参数nus:需要延时的us数 * 返回值:无*/ void delay_us(uint32_t nus) { uint32_t ticks; uint32_t told, tnow, tcnt = 0; uint32_t reload = SysTick->LOAD; /* 滴答定时器的重装载值 */ ticks = nus * 120; /* 需要的节拍数 */ told = SysTick->VAL; /* 刚进入时的计数器值 */ while(1) { tnow = SysTick->VAL; if(tnow != told) { if(tnow = ticks)break; /* 时间超过/等于要延迟的时间,则退出. */ told = tnow; } } }

模拟IIC通信的函数如下

/* 描述:启动I2C总线,即发送I2C起始条件. * 参数: 无 * 返回值:无 */ void IIC_Start(void) { SDA_OUT(); IIC_SDA(1); IIC_SCL(1); delay_us(4); IIC_SDA(0); delay_us(4); IIC_SCL(0); } /* 描述:结束I2C总线,即发送I2C结束条件. * 参数: 无 * 返回值:无 */ void IIC_Stop(void) { SDA_OUT(); IIC_SCL(0); IIC_SDA(0); delay_us(4); IIC_SCL(1); delay_us(4); IIC_SDA(1); delay_us(4); } /* 描述:发送应答 ACK * 参数: 无 * 返回值:无 */ void IIC_ACK(void) { SDA_OUT(); IIC_SCL(0); delay_us(2); IIC_SDA(0); delay_us(2); IIC_SCL(1); delay_us(2); IIC_SCL(0); delay_us(1); } /* 描述:发送非应答 NACK * 参数: 无 * 返回值:无 */ void IIC_NACK(void) { SDA_OUT(); IIC_SCL(0); delay_us(2); IIC_SDA(1); delay_us(2); IIC_SCL(1); delay_us(2); IIC_SCL(0); delay_us(1); } /* 描述:等待ACK * 参数: 无 * 返回值:等待应答返回0,没有等待到应答返回1 */ uint8_t IIC_wait_ACK(void) { uint8_t t = 200; SDA_OUT(); IIC_SDA(1); delay_us(1); IIC_SCL(0); delay_us(1); SDA_IN(); /* 数据发送完后释放数据线,准备接收应答位 */ delay_us(1); while(READ_SDA) /* 等待IIC应答*/ { t--; delay_us(1); if(t==0) { IIC_SCL(0); return 1; } delay_us(1); } delay_us(1); IIC_SCL(1); delay_us(1); IIC_SCL(0); delay_us(1); return 0; } /* 描述:一个字节数据发送函数 * 参数: 无 * 返回值:无 */ void IIC_SendByte(uint8_t byte) { uint8_t BitCnt; SDA_OUT(); IIC_SCL(0); for(BitCnt=0;BitCnt uint8_t retc; uint8_t BitCnt; retc=0; SDA_IN(); /* 设置数据线为输入方式 */ delay_us(1); for(BitCnt=0;BitCnt /* 软件复位命令 */ SOFT_RESET_CMD = 0x30A2, /* 单次测量模式 命名格式:Repeatability_CS_CMD CS: Clock stretching */ HIGH_ENABLED_CMD = 0x2C06, MEDIUM_ENABLED_CMD = 0x2C0D, LOW_ENABLED_CMD = 0x2C10, HIGH_DISABLED_CMD = 0x2400, MEDIUM_DISABLED_CMD = 0x240B, LOW_DISABLED_CMD = 0x2416, /* 周期测量模式 命名格式:Repeatability_MPS_CMD MPS:measurement per second */ HIGH_0_5_CMD = 0x2032, MEDIUM_0_5_CMD = 0x2024, LOW_0_5_CMD = 0x202F, HIGH_1_CMD = 0x2130, MEDIUM_1_CMD = 0x2126, LOW_1_CMD = 0x212D, HIGH_2_CMD = 0x2236, MEDIUM_2_CMD = 0x2220, LOW_2_CMD = 0x222B, HIGH_4_CMD = 0x2334, MEDIUM_4_CMD = 0x2322, LOW_4_CMD = 0x2329, HIGH_10_CMD = 0x2737, MEDIUM_10_CMD = 0x2721, LOW_10_CMD = 0x272A, /* 周期测量模式读取数据命令 */ READOUT_FOR_PERIODIC_MODE = 0xE000, /* 读取传感器编号命令 */ READ_SERIAL_NUMBER = 0x3780, } SHT3X_CMD; #endif

在sht3x.c文件中,先将读写标志以及SHT30的地址设置好:

#define write 0 #define read 1 uint8_t addr = 0x44; //设置传感器地址

然后就是发送命令和接收数据函数

/* 描述:向SHT30发送一条16bit指令 * 参数cmd:SHT30指令(在SHT30_MODE中枚举定义) * 返回值:发送成功返回0,发送失败返回1 */ static uint8_t SHT3x_Send_Cmd(SHT3X_CMD cmd) { uint8_t cmd_buffer[2]; uint8_t ret; cmd_buffer[0] = cmd >> 8; cmd_buffer[1] = cmd; IIC_SendByte(addr data_arr[i]=IIC_RcvByte(); IIC_ACK(); } data_arr[i]=IIC_RcvByte(); IIC_NACK(); return 0; }

接下来我们测试一下读取传感器的编号

/* 描述:读取传感器编号 * 参数:存储编号数据的指针 * 返回值:0-读取成功,1-读取失败 */ uint8_t SHT3x_ReadSerialNumber(uint32_t* serialNumber) { uint8_t ret = 0; uint8_t Num_buf[4] = {0xFF,0xFF,0xFF,0xFF}; IIC_Start(); SHT3x_Send_Cmd(READ_SERIAL_NUMBER); IIC_Stop(); delay_1ms(10); /* 有问题时需要适当延长!!!!!!*/ IIC_Start(); ret = SHT3x_Recv_Data(4,Num_buf); IIC_Stop(); *serialNumber = ((Num_buf[0] remainder ^= message[j]; /* 从最高位开始依次计算 */ for (i = 0; i uint8_t ret=0; uint8_t buff[6]; uint16_t tem,hum; double Temperature=0; double Humidity=0; IIC_Start(); ret = SHT3x_Send_Cmd(READOUT_FOR_PERIODIC_MODE); IIC_Start(); ret = SHT3x_Recv_Data(6,buff); IIC_Stop(); /* 校验温度数据和湿度数据是否接收正确 */ if(CheckCrc8(buff, 0xFF) != buff[2] || CheckCrc8(&buff[3], 0xFF) != buff[5]) { printf("CRC_ERROR,ret = 0x%x\r\n",ret); return 1; } /* 转换温度数据 */ tem = (((uint16_t)buff[0] delay_1ms(1000); if(SHT3x_Get_Humiture_periodic(&Tem_val,&Hum_val) == 0) printf("Tem_val:%f C,\t&Hum_val:%f %%Rh\r\n",Tem_val,Hum_val); else printf("Get_Humiture ERR\r\n"); }

编译下载运行,可以得到,读取数据成功 在这里插入图片描述 另外,也可以单次读取

/* 描述:温湿度数据获取函数,单次获取 * 参数Tem_val:存储温度数据的指针, 温度单位为°C * 参数Hum_val:存储湿度数据的指针, 温度单位为% * 返回值:0-读取成功,1-读取失败 ********************************************************************/ uint8_t SHT3x_Get_Humiture_single(double *Tem_val,double *Hum_val) { uint8_t ret=0; uint8_t buff[6]; uint16_t tem,hum; double Temperature=0; double Humidity=0; IIC_Start(); SHT3x_Send_Cmd(HIGH_ENABLED_CMD); IIC_Stop(); delay_1ms(50); IIC_Start(); ret = SHT3x_Recv_Data(6,buff); IIC_Stop(); /* 校验温度数据和湿度数据是否接收正确 */ if(CheckCrc8(buff, 0xFF) != buff[2] || CheckCrc8(&buff[3], 0xFF) != buff[5]) { printf("CRC_ERROR,ret = 0x%x\r\n",ret); return 1; } /* 转换温度数据 */ tem = (((uint16_t)buff[0] // uint32_t sn; char res_buf[128]; char data_buf[128]; int times = 0; double Tem_val,Hum_val; systick_config(); /* 配置系统时钟 */ LED_init(); /* 初始化 LED */ uart_init(115200); /* 初始化USART0 */ uart1_init(9600); /* 初始化USART1 */ timer5_init(50000,12000); /* 定时5000ms*/ printf("Hello world! \r\n"); while(NB_Start()) { u1_printf("AT+NRB\r\n"); /* 重启*/ while(USART1_RX_NUM == 0) ; if(USART1_RX_NUM >0) { printf("NBIoT: %s\r\n",rx1_date_buf); USART1_RX_NUM = 0; } } printf("start OK\r\n"); // IIC_Init(); // if( 0 == SHT3x_ReadSerialNumber(&sn)) // printf("ReadSerialNumber OK sn = 0x%x \r\n",sn); // else // printf("ReadSerialNumber ERR \r\n"); if( 0 == SHT3x_Init()) printf("SHT3x_Init OK \r\n"); else printf("SHT3x_Init ERR \r\n"); while(1) { if(update_flag == 1) { update_flag = 0; times++; LED(times%2); /* 采集温湿度数据然后上传到EMQ */ if(SHT3x_Get_Humiture_periodic(&Tem_val,&Hum_val) == 0) { sprintf(data_buf,"{\"temperature\":%6.2lf ,\"humidity\":%6.2lf }",Tem_val,Hum_val); NB_Send_data("39.96.35.207", "SHT3x", data_buf); printf("%s\r\nData send to EMQ...\r\n",data_buf); } else printf("Get_Humiture ERR\r\n"); } if(USART1_RX_NUM >0) { USART1_RX_NUM = 0; if(Find_string((char *)rx1_date_buf,"+NSONMI:","\r\n",res_buf)>0) { u1_printf("AT+NSORF=%d,%d\r\n",udp_socket,res_buf[2]-'0'); } printf("NBIOT: %s\r\n",rx1_date_buf); } if(USART_RX_NUM >0) { USART_RX_NUM = 0; u1_printf("%s",rx0_date_buf); } } }

编译下载运行,可以看到,在EMQ上接收到数据 在这里插入图片描述

四、代码

完整代码我存放在码云,可以查看:https://gitee.com/william_william/GD32.git



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有