[STM32#14] DHT-11과 AHT-10(i2c) 온습도센서를 STM32f103rb nucleo에 연결해서 온도와 습도를 측정하는 방법 알아보기!(녹칸다 내맘대로 STM32)
프로그래밍/STM32 2025. 11. 26. 18:52
https://youtube.com/live/DxaNkZ3ZAoU
[STM32#14] DHT-11과 AHT-10(i2c) 온습도센서를 STM32f103rb nucleo에 연결해서 온도와 습도를 측정하는 방법 알아보기!(녹칸다 내맘대로 STM32)
심심한녹칸다의 내맘대로 STM32시리즈이다!
STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g39a118d174f_1_193#slide=id.g39a118d174f_1_193
이번편은 온습도센서 2종세트 입니다~!
(DHT-11연결도)

(DHT-11 코드)
#define delay_ms HAL_Delay
#define SYS_CLOCK 64
#define SYSTICK_LOAD 63999
uint32_t millis_cnt = 0;
uint32_t millis() {
return millis_cnt;
}
uint32_t micros() {
return (millis_cnt & 0x3FFFFF) * 1000 + (SYSTICK_LOAD - SysTick->VAL) / SYS_CLOCK;
}
void delay_us(uint32_t us) { // 64MHz 보정
if (us > 1) {
uint32_t count = us * 7 - 6;
while (count--);
} else {
uint32_t count = 2;
while (count--);
}
}
union {
uint32_t data;
struct {
uint8_t temp_d;
uint8_t temp_i;
uint8_t rh_d;
uint8_t rh_i;
};
} DHT;
uint8_t DHT_read () {
uint8_t i, check_sum;
uint32_t start;
check_sum = 0;
DHT.data = 0;
GPIOC->CRL = (GPIOC->CRL&0xFFFFFF0F)|(7<<(1*4)); // Output Open-drain (Master send LOW signal)
delay_ms(18);
GPIOC->CRL= (GPIOC->CRL&0xFFFFFF0F)|(4<<(1*4)); // Floating input (Master send HIGH signal & data receive)
start = micros();
while (GPIOC->IDR&(1<<1)) {
if (micros()-start > 50) return 1; // 20~40us
}
start = micros();
while (!(GPIOC->IDR&(1<<1))) {
if (micros()-start > 120) return 2; // 80us
}
start = micros();
while (GPIOC->IDR&(1<<1)) {
if (micros()-start > 120) return 3; // 80us
}
for (i = 0; i < 32; i++) {
while (!(GPIOC->IDR&(1<<1))); // 50us
start = micros();
while (GPIOC->IDR&(1<<1));
if (micros()-start > 50) DHT.data |= (0x80000000 >> i); // "0"=26~28us, "1"=70us
}
for (i = 0; i < 8; i++) {
while (!(GPIOC->IDR&(1<<1))); // 50us
start = micros();
while (GPIOC->IDR&(1<<1));
if (micros()-start > 50) check_sum |= (0x80 >> i);
}
if ((DHT.rh_i + DHT.rh_d + DHT.temp_i + DHT.temp_d) == check_sum) return 0;
else return 4;
}
(AHT-10 연결도)

(AHT-10 추가코드)
uint8_t AHT10_TmpHum_Cmd[3] = {0xAC, 0x33, 0x00};
uint8_t AHT10_RX_Data[6];
uint32_t AHT10_ADC_Raw;
float AHT10_Temperature;
float AHT10_Humidity;
char str[100];
//요청
HAL_I2C_Master_Transmit(&hi2c1, (0x38 << 1), AHT10_TmpHum_Cmd, 3, 10);
//수신대기
uint8_t recv[1];
while(1){
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), recv, 6, 10);
if(~recv[0] & 0x80){
break;
}
}
//데이터 수신
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), AHT10_RX_Data, 6, 10);
//수신데이터 출력
AHT10_ADC_Raw = (((uint32_t)AHT10_RX_Data[3] & 15) << 16) | ((uint32_t)AHT10_RX_Data[4] << 8) | AHT10_RX_Data[5];
AHT10_Temperature = (float)(AHT10_ADC_Raw * 200.00 / 1048576.00) - 50.00;
/* Convert to Relative Humidity in % */
AHT10_ADC_Raw = ((uint32_t)AHT10_RX_Data[1] << 12) | ((uint32_t)AHT10_RX_Data[2] << 4) | (AHT10_RX_Data[3] >> 4);
AHT10_Humidity = (float)(AHT10_ADC_Raw*100.00/1048576.00);
sprintf(str,"%f, %f\r\n",AHT10_Temperature,AHT10_Humidity);
HAL_UART_Transmit(&huart2,str,strlen(str),100);
(예제목차)
1.DHT-11의 기본예제를 이용해서 온도와 습도값을 usart2로 출력해서 putty에 터미널로 값을 확인하시오!

/* USER CODE BEGIN 2 */
char str[100];
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint8_t error_no = DHT_read();
if(error_no == 0){ // 정상일 때 처리
float temp = 0;
float humi = 0;
temp = DHT.temp_i;
if (DHT.temp_d & 0x80) {
temp = -1 - temp;
}
temp += (DHT.temp_d & 0x0f) * 0.1;
humi = DHT.rh_i + DHT.rh_d * 0.1;
sprintf(str, "T:%.1f'C H:%.1f%c\n", temp,humi,'%');
HAL_UART_Transmit(&huart2,str,strlen(str),100);
} else {
sprintf(str, "Error=%d\n", error_no);
HAL_UART_Transmit(&huart2,str,strlen(str),100);
}
HAL_Delay(2000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
2.측정한 온도와 습도값을 I2C통신을 하는 1602LCD에 출력하시오!(I2C설정을 IOC에서 할 것)

/* USER CODE BEGIN 2 */
char str[100];
LCD_INIT(); //1회호출(메인루프 시작전)
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint8_t error_no = DHT_read();
if(error_no == 0){ // 정상일 때 처리
float temp = 0;
float humi = 0;
temp = DHT.temp_i;
if (DHT.temp_d & 0x80) {
temp = -1 - temp;
}
temp += (DHT.temp_d & 0x0f) * 0.1;
humi = DHT.rh_i + DHT.rh_d * 0.1;
sprintf(str, "T:%.1f'C H:%.1f%c", temp,humi,'%');
LCD_CLEAR();//원래 있던거 삭제!
LCD_XY(0, 0) ; LCD_PUTS("NOCKANDA DHT11");
LCD_XY(0, 1) ; LCD_PUTS(str);
}
HAL_Delay(2000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
3.측정한 온도와 습도를 FND모듈인 TM1637에 출력하는데, 소수점이하는 버리고 숫자 2개씩 해서 왼쪽 2칸은 온도, 오른쪽 2칸은 습도로 출력하시오!

/* USER CODE BEGIN 2 */
char str[100];
tm1637Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint8_t error_no = DHT_read();
if(error_no == 0){ // 정상일 때 처리
float temp = 0;
float humi = 0;
temp = DHT.temp_i;
if (DHT.temp_d & 0x80) {
temp = -1 - temp;
}
temp += (DHT.temp_d & 0x0f) * 0.1;
humi = DHT.rh_i + DHT.rh_d * 0.1;
int data = ((int)temp * 100) + (int)humi;
tm1637DisplayDecimalTrim(data,0);
}
HAL_Delay(2000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
4.STM32가 DHT11의 온습도값을 2초간격으로 측정한다! 그리고 FND모듈에 1초간격으로 한번은 온도, 한번은 습도를 출력한다! 이때 소수점값을 출력한다!

/* USER CODE BEGIN 2 */
char str[100];
tm1637Init();
uint32_t t1 = 0; //온습도값 2초
uint32_t t2 = 0; //FND출력 1초
float temp = 0;
float humi = 0;
uint8_t sw = 0; //0이면 온도, 1이면 습도
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//2초간격으로 temp와 humi에 값을 입력만 한다!
if(HAL_GetTick() - t1 >= 2000){
t1 = HAL_GetTick();
uint8_t error_no = DHT_read();
if(error_no == 0){ // 정상일 때 처리
temp = DHT.temp_i;
if (DHT.temp_d & 0x80) {
temp = -1 - temp;
}
temp += (DHT.temp_d & 0x0f) * 0.1;
humi = DHT.rh_i + DHT.rh_d * 0.1;
}
}
//1초간격으로 온도와 습도를 번갈아가면서 출력한다!
if(HAL_GetTick() - t2 >= 1000){
t2 = HAL_GetTick();
if(sw == 0){
//온도
tm1637DisplayDecimalTrim((int)(temp*100),1);
tm1637SetRawSegment(3,0b00111001);
sw = 1;
}else if(sw == 1){
//습도
tm1637DisplayDecimalTrim((int)(humi*100),1);
tm1637SetRawSegment(3,0b01001001);
sw = 0;
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
5.이번에는 AHT-10온습도센서값을 usart2통신으로 터미널에 출력해서 확인하시오!

/* USER CODE BEGIN 2 */
uint8_t AHT10_TmpHum_Cmd[3] = {0xAC, 0x33, 0x00};
uint8_t AHT10_RX_Data[6];
uint32_t AHT10_ADC_Raw;
float AHT10_Temperature;
float AHT10_Humidity;
char str[100];
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//요청
HAL_I2C_Master_Transmit(&hi2c1, (0x38 << 1), AHT10_TmpHum_Cmd, 3, 10);
//수신대기
uint8_t recv[1];
while(1){
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), recv, 6, 10);
if(~recv[0] & 0x80){
break;
}
}
//데이터 수신
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), AHT10_RX_Data, 6, 10);
//수신데이터 출력
AHT10_ADC_Raw = (((uint32_t)AHT10_RX_Data[3] & 15) << 16) | ((uint32_t)AHT10_RX_Data[4] << 8) | AHT10_RX_Data[5];
AHT10_Temperature = (float)(AHT10_ADC_Raw * 200.00 / 1048576.00) - 50.00;
/* Convert to Relative Humidity in % */
AHT10_ADC_Raw = ((uint32_t)AHT10_RX_Data[1] << 12) | ((uint32_t)AHT10_RX_Data[2] << 4) | (AHT10_RX_Data[3] >> 4);
AHT10_Humidity = (float)(AHT10_ADC_Raw*100.00/1048576.00);
sprintf(str,"TEMP:%.2f'C, HUMI:%.2f%c\n",AHT10_Temperature,AHT10_Humidity,'%');
HAL_UART_Transmit(&huart2,str,strlen(str),100);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
6.AHT-10에서 측정한 온도와 습도값을 1602LCD화면에 보기 좋게 출력하시오!

/* USER CODE BEGIN 2 */
uint8_t AHT10_TmpHum_Cmd[3] = {0xAC, 0x33, 0x00};
uint8_t AHT10_RX_Data[6];
uint32_t AHT10_ADC_Raw;
float AHT10_Temperature;
float AHT10_Humidity;
char str[100];
LCD_INIT();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//요청
HAL_I2C_Master_Transmit(&hi2c1, (0x38 << 1), AHT10_TmpHum_Cmd, 3, 10);
//수신대기
uint8_t recv[1];
while(1){
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), recv, 6, 10);
if(~recv[0] & 0x80){
break;
}
}
//데이터 수신
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), AHT10_RX_Data, 6, 10);
//수신데이터 출력
AHT10_ADC_Raw = (((uint32_t)AHT10_RX_Data[3] & 15) << 16) | ((uint32_t)AHT10_RX_Data[4] << 8) | AHT10_RX_Data[5];
AHT10_Temperature = (float)(AHT10_ADC_Raw * 200.00 / 1048576.00) - 50.00;
/* Convert to Relative Humidity in % */
AHT10_ADC_Raw = ((uint32_t)AHT10_RX_Data[1] << 12) | ((uint32_t)AHT10_RX_Data[2] << 4) | (AHT10_RX_Data[3] >> 4);
AHT10_Humidity = (float)(AHT10_ADC_Raw*100.00/1048576.00);
sprintf(str, "T:%.1f'C H:%.1f%c", AHT10_Temperature,AHT10_Humidity,'%');
LCD_CLEAR();//원래 있던거 삭제!
LCD_XY(0, 0) ; LCD_PUTS("NOCKANDA AHT-10!");
LCD_XY(0, 1) ; LCD_PUTS(str);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
7.녹칸다의 STM32쉴드에서 링모양으로 배치된 LED가 8개있는데, 12시방향을 시작으로 해서 온도 3도당 LED가 1개씩 켜지도록 하시오!

/* USER CODE BEGIN 2 */
uint8_t AHT10_TmpHum_Cmd[3] = {0xAC, 0x33, 0x00};
uint8_t AHT10_RX_Data[6];
uint32_t AHT10_ADC_Raw;
float AHT10_Temperature;
float AHT10_Humidity;
char str[100];
LCD_INIT();
GPIO_TypeDef *mygpio[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//요청
HAL_I2C_Master_Transmit(&hi2c1, (0x38 << 1), AHT10_TmpHum_Cmd, 3, 10);
//수신대기
uint8_t recv[1];
while(1){
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), recv, 6, 10);
if(~recv[0] & 0x80){
break;
}
}
//데이터 수신
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), AHT10_RX_Data, 6, 10);
//수신데이터 출력
AHT10_ADC_Raw = (((uint32_t)AHT10_RX_Data[3] & 15) << 16) | ((uint32_t)AHT10_RX_Data[4] << 8) | AHT10_RX_Data[5];
AHT10_Temperature = (float)(AHT10_ADC_Raw * 200.00 / 1048576.00) - 50.00;
/* Convert to Relative Humidity in % */
AHT10_ADC_Raw = ((uint32_t)AHT10_RX_Data[1] << 12) | ((uint32_t)AHT10_RX_Data[2] << 4) | (AHT10_RX_Data[3] >> 4);
AHT10_Humidity = (float)(AHT10_ADC_Raw*100.00/1048576.00);
sprintf(str, "T:%.1f'C H:%.1f%c", AHT10_Temperature,AHT10_Humidity,'%');
LCD_CLEAR();//원래 있던거 삭제!
LCD_XY(0, 0) ; LCD_PUTS("NOCKANDA AHT-10!");
LCD_XY(0, 1) ; LCD_PUTS(str);
int last_index = (int)(AHT10_Temperature/3);
if(last_index > 7) last_index = 7;
for(int i =0;i<8;i++){
if(i <= last_index){
HAL_GPIO_WritePin(mygpio[i], mypin[i], 1);
}else{
HAL_GPIO_WritePin(mygpio[i], mypin[i], 0);
}
}
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
8.DHT-11값과 AHT-10의값을 둘다 측정해서 1602LCD에 출력하시오!

/* USER CODE BEGIN 2 */
uint8_t AHT10_TmpHum_Cmd[3] = {0xAC, 0x33, 0x00};
uint8_t AHT10_RX_Data[6];
uint32_t AHT10_ADC_Raw;
float AHT10_Temperature;
float AHT10_Humidity;
char str[100];
LCD_INIT();
float temp = 0;
float humi = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//요청
HAL_I2C_Master_Transmit(&hi2c1, (0x38 << 1), AHT10_TmpHum_Cmd, 3, 10);
//수신대기
uint8_t recv[1];
while(1){
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), recv, 6, 10);
if(~recv[0] & 0x80){
break;
}
}
//데이터 수신
HAL_I2C_Master_Receive(&hi2c1, (0x38 << 1), AHT10_RX_Data, 6, 10);
//수신데이터 출력
AHT10_ADC_Raw = (((uint32_t)AHT10_RX_Data[3] & 15) << 16) | ((uint32_t)AHT10_RX_Data[4] << 8) | AHT10_RX_Data[5];
AHT10_Temperature = (float)(AHT10_ADC_Raw * 200.00 / 1048576.00) - 50.00;
/* Convert to Relative Humidity in % */
AHT10_ADC_Raw = ((uint32_t)AHT10_RX_Data[1] << 12) | ((uint32_t)AHT10_RX_Data[2] << 4) | (AHT10_RX_Data[3] >> 4);
AHT10_Humidity = (float)(AHT10_ADC_Raw*100.00/1048576.00);
uint8_t error_no = DHT_read();
if(error_no == 0){ // 정상일 때 처리
temp = DHT.temp_i;
if (DHT.temp_d & 0x80) {
temp = -1 - temp;
}
temp += (DHT.temp_d & 0x0f) * 0.1;
humi = DHT.rh_i + DHT.rh_d * 0.1;
}
LCD_CLEAR();//원래 있던거 삭제!
sprintf(str, "T:%.1f'C H:%.1f%c", temp,humi,'%');
LCD_XY(0, 0) ; LCD_PUTS(str);
sprintf(str, "T:%.1f'C H:%.1f%c", AHT10_Temperature,AHT10_Humidity,'%');
LCD_XY(0, 1) ; LCD_PUTS(str);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}

