基于I2C的温湿度采集
硬件I2C和软件I2C温湿度采集任务要求硬件连接添加代码最终效果硬件I2C和软件I2C
硬件I2C对应芯片上的baiI2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的;
软件I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C的效率要高于软件模拟的,软件模拟I2C是通过GPIO,软件模拟寄存器的工作方式,而硬件I2C是直接调用内部寄存器进行配置;
STM32 的 I2C 片上外设专门负责实现 I2C 通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理 I2C协议的方式减轻了 CPU 的工作,且使软件设计更加简单。
温湿度采集
任务要求
编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win10)。
硬件连接
AHT20的SCL,GND,SDA,VCC分别对应接stm32f103指南者I2c模块的PB6,GND,PB7,5V。
添加代码
利用野火的例子工程BH-F103并将下列代码添加进工程
主函数main.c
#include "delay.h"#include "usart.h"#include "i2c.h"int main(void){delay_init(); uart_init(115200); IIC_Init();while(1){printf("开始测量,请稍等");read_AHT20_once();delay_ms(1500);}}
delay.c
#include "delay.h"#include "sys.h"#if SYSTEM_SUPPORT_UCOS#include "includes.h" #endifstatic u8 fac_us=0;static u16 fac_ms=0;#ifdef OS_CRITICAL_METHOD void SysTick_Handler(void){OSIntEnter();OSTimeTick();OSIntExit();#endifvoid delay_init() {#ifdef OS_CRITICAL_METHOD u32 reload;#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);fac_us=SystemCoreClock/8000000; #ifdef OS_CRITICAL_METHOD reload=SystemCoreClock/8000000; reload*=1000000/OS_TICKS_PER_SEC;fac_ms=1000/OS_TICKS_PER_SEC; SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;SysTick->LOAD=reload;SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; #elsefac_ms=(u16)fac_us*1000;#endif} #ifdef OS_CRITICAL_METHOD void delay_us(u32 nus){u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD;ticks=nus*fac_us; tcnt=0;told=SysTick->VAL; while(1){tnow=SysTick->VAL;if(tnow!=told){if(tnow<told)tcnt+=told-tnow;else tcnt+=reload-tnow+told; told=tnow;if(tcnt>=ticks)break;} };}void delay_ms(u16 nms){if(OSRunning==TRUE) {if(nms>=fac_ms){OSTimeDly(nms/fac_ms);}nms%=fac_ms;}delay_us((u32)(nms*1000));}#else void delay_us(u32 nus){u32 temp;SysTick->LOAD=nus*fac_us; SysTick->VAL=0x00; SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16)));SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; SysTick->VAL =0X00; }void delay_ms(u16 nms){u32 temp; SysTick->LOAD=(u32)nms*fac_ms;SysTick->VAL =0x00;SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;do{temp=SysTick->CTRL;}while(temp&0x01&&!(temp&(1<<16))); SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; SysTick->VAL =0X00; } #endif
usart.c
#include "sys.h"#include "usart.h"#if SYSTEM_SUPPORT_UCOS#include "includes.h"#if 1#pragma import(__use_no_semihosting) struct __FILE {int handle; }; FILE __stdout; void _sys_exit(int x) {x = x; } int fputc(int ch, FILE *f){while((USART1->SR&0X40)==0); USART1->DR = (u8) ch;return ch;}#endif #if EN_USART1_RX u8 USART_RX_BUF[USART_REC_LEN]; u16 USART_RX_STA=0; void uart_init(u32 bound){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);USART_InitStructure.USART_BaudRate = bound;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_Cmd(USART1, ENABLE); }void USART1_IRQHandler(void) {u8 Res;#ifdef OS_TICKS_PER_SECOSIntEnter(); #endifif(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {Res =USART_ReceiveData(USART1);//(USART1->DR);if((USART_RX_STA&0x8000)==0){if(USART_RX_STA&0x4000){if(Res!=0x0a)USART_RX_STA=0;else USART_RX_STA|=0x8000;}else {if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; } }} } #ifdef OS_TICKS_PER_SEC OSIntExit(); #endif} #endif
i2C.c
#include "i2c.h"#include "delay.h"uint8_t ack_status=0;uint8_t readByte[6];uint8_t AHT20_status=0;uint32_t H1=0; //Humilityuint32_t T1=0; //Temperatureuint8_t AHT20_OutData[4];uint8_t AHT20sendOutData[10] = {0xFA, 0x06, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};void IIC_Init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //ÍÆÍìÊä³öGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);IIC_SCL=1;IIC_SDA=1;}void IIC_Start(void){SDA_OUT(); IIC_SDA=1; IIC_SCL=1;delay_us(4);IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4);IIC_SCL=0;} void IIC_Stop(void){SDA_OUT();IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(4);IIC_SCL=1; IIC_SDA=1;delay_us(4); }u8 IIC_Wait_Ack(void){u8 ucErrTime=0;SDA_IN(); IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;return 0; } void IIC_Ack(void){IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;}//²»²úÉúACKÓ¦´ð void IIC_NAck(void){IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;} void IIC_Send_Byte(u8 txd){u8 t; SDA_OUT();IIC_SCL=0;for(t=0;t<8;t++){IIC_SDA=(txd&0x80)>>7;txd<<=1; delay_us(2); IIC_SCL=1;delay_us(2); IIC_SCL=0;delay_us(2);} }u8 IIC_Read_Byte(unsigned char ack){unsigned char i,receive=0;SDA_IN();for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA)receive++; delay_us(1); } if (!ack)IIC_NAck();elseIIC_Ack(); return receive;} void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr){IIC_Start(); if(device_addr==0xA0) IIC_Send_Byte(0xA0 + ((addr/256)<<1));elseIIC_Send_Byte(device_addr); IIC_Wait_Ack(); IIC_Send_Byte(addr&0xFF); IIC_Wait_Ack(); IIC_Send_Byte(data); IIC_Wait_Ack(); IIC_Stop();if(device_addr==0xA0)delay_ms(10);elsedelay_us(2);}uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead) {uint16_t data;IIC_Start(); if(device_addr==0xA0)IIC_Send_Byte(0xA0 + ((addr/256)<<1));elseIIC_Send_Byte(device_addr);IIC_Wait_Ack();IIC_Send_Byte(addr&0xFF); IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(device_addr+1);IIC_Wait_Ack();if(ByteNumToRead == 1){data=IIC_Read_Byte(0);}else{data=IIC_Read_Byte(1);data=(data<<8)+IIC_Read_Byte(0);}IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ return data;}void read_AHT20_once(void){delay_ms(10);startMeasure_AHT20();delay_ms(80);read_AHT20();delay_ms(5);}void startMeasure_AHT20(void){I2C_Start();I2C_WriteByte(0x70);ack_status = Receive_ACK();if(ack_status);else printf("7-n-");I2C_WriteByte(0xAC);ack_status = Receive_ACK();if(ack_status);else printf("8-n-");I2C_WriteByte(0x33);ack_status = Receive_ACK();if(ack_status);else printf("9-n-");I2C_WriteByte(0x00);ack_status = Receive_ACK();if(ack_status);else printf("10-n-");I2C_Stop();}void read_AHT20(void){uint8_t i;for(i=0; i<6; i++){readByte[i]=0;}I2C_Start();I2C_WriteByte(0x71);ack_status = Receive_ACK();readByte[0]= I2C_ReadByte();Send_ACK();readByte[1]= I2C_ReadByte();Send_ACK();readByte[2]= I2C_ReadByte();Send_ACK();readByte[3]= I2C_ReadByte();Send_ACK();readByte[4]= I2C_ReadByte();Send_ACK();readByte[5]= I2C_ReadByte();SendNot_Ack();//Send_ACK();I2C_Stop();if( (readByte[0] & 0x68) == 0x08 ){H1 = readByte[1];H1 = (H1<<8) | readByte[2];H1 = (H1<<8) | readByte[3];H1 = H1>>4;H1 = (H1*1000)/1024/1024;T1 = readByte[3];T1 = T1 & 0x0000000F;T1 = (T1<<8) | readByte[4];T1 = (T1<<8) | readByte[5];T1 = (T1*2000)/1024/1024 - 500;AHT20_OutData[0] = (H1>>8) & 0x000000FF;AHT20_OutData[1] = H1 & 0x000000FF;AHT20_OutData[2] = (T1>>8) & 0x000000FF;AHT20_OutData[3] = T1 & 0x000000FF;}else{AHT20_OutData[0] = 0xFF;AHT20_OutData[1] = 0xFF;AHT20_OutData[2] = 0xFF;AHT20_OutData[3] = 0xFF;printf("失败了");}printf("\r\n");printf("当前温度为: %d%d.%d",T1/100,(T1/10)%10,T1%10);printf("\r\n");printf("当前湿度为: %d%d.%d",H1/100,(H1/10)%10,H1%10);printf("\r\n");}uint8_t Receive_ACK(void){uint8_t result=0;uint8_t cnt=0;IIC_SCL = 0;SDA_IN(); delay_us(4);IIC_SCL = 1;delay_us(4);while(READ_SDA && (cnt<100)){cnt++;}IIC_SCL = 0;delay_us(4);if(cnt<100){result=1;}return result;}void Send_ACK(void){SDA_OUT();IIC_SCL = 0;delay_us(4);IIC_SDA = 0;delay_us(4);IIC_SCL = 1;delay_us(4);IIC_SCL = 0;delay_us(4);SDA_IN();}void SendNot_Ack(void){SDA_OUT();IIC_SCL = 0;delay_us(4);IIC_SDA = 1;delay_us(4);IIC_SCL = 1;delay_us(4);IIC_SCL = 0;delay_us(4);IIC_SDA = 0;delay_us(4);}void I2C_WriteByte(uint8_t input){uint8_t i;SDA_OUT();for(i=0; i<8; i++){IIC_SCL = 0;delay_ms(5);if(input & 0x80){IIC_SDA = 1;//delaymm(10);}else{IIC_SDA = 0;//delaymm(10);}IIC_SCL = 1;delay_ms(5);input = (input<<1);}IIC_SCL = 0;delay_us(4);SDA_IN();delay_us(4);}uint8_t I2C_ReadByte(void){uint8_t resultByte=0;uint8_t i=0, a=0;IIC_SCL = 0;SDA_IN();delay_ms(4);for(i=0; i<8; i++){IIC_SCL = 1;delay_ms(3);a=0;if(READ_SDA){a=1;}else{a=0;}//resultByte = resultByte | a;resultByte = (resultByte << 1) | a;IIC_SCL = 0;delay_ms(3);}SDA_IN();delay_ms(10);return resultByte;}void set_AHT20sendOutData(void){AHT20sendOutData[3] = AHT20_OutData[0];AHT20sendOutData[4] = AHT20_OutData[1];AHT20sendOutData[5] = AHT20_OutData[2];AHT20sendOutData[6] = AHT20_OutData[3];}void I2C_Start(void){SDA_OUT();IIC_SCL = 1;delay_ms(4);IIC_SDA = 1;delay_ms(4);IIC_SDA = 0;delay_ms(4);IIC_SCL = 0;delay_ms(4);}void I2C_Stop(void){SDA_OUT();IIC_SDA = 0;delay_ms(4);IIC_SCL = 1;delay_ms(4);IIC_SDA = 1;delay_ms(4);}
sys.c
#include "sys.h"void NVIC_Configuration(void){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);}
usart.h
#ifndef __USART_H#define __USART_H#include "stdio.h"#include "sys.h" #define USART_REC_LEN #define EN_USART1_RX extern u8 USART_RX_BUF[USART_REC_LEN];extern u16 USART_RX_STA; void uart_init(u32 bound);#endif
delay.h
#ifndef __DELAY_H#define __DELAY_H #include "sys.h"void delay_init(void);void delay_ms(u16 nms);void delay_us(u32 nus);#endif
最终效果
最后下载烧录进STM32后,打开串口助手,结果如下
当朝着AHT20呼气时,显然温度与湿度都上升了,测试正确。