#include <stdio.h> #include <stm32f10x.h>
#define RS_0 (GPIOA->BRR = GPIO_BRR_BR0) #define RS_1 (GPIOA->BSRR = GPIO_BSRR_BS0) #define RW_0 (GPIOA->BRR = GPIO_BRR_BR1) #define RW_1 (GPIOA->BSRR = GPIO_BSRR_BS1) #define E_0 (GPIOA->BRR = GPIO_BRR_BR2) #define E_1 (GPIOA->BSRR = GPIO_BSRR_BS2)
#define DHT11_W0 (GPIOB->BRR = GPIO_BRR_BR0) #define DHT11_W1 (GPIOB->BSRR = GPIO_BSRR_BS0) #define DHT11_R ((GPIOB->IDR & GPIO_IDR_IDR0) != 0)
#define MANTISSA(n) ((uint8_t)((n) * 390625 / 1e6)) // 保留两位小数
// 延时n毫秒(0<n<6553) void delay_ms(uint16_t nms) { TIM1->ARR = nms * 10 - 1; // 从0计数到9为1ms, UIF在CNT=0时置位 TIM1->PSC = 7199; // 72000kHz/7200=10kHz -> 0.1ms TIM1->EGR = TIM_EGR_UG; // 保存上面的设置 TIM1->SR &= ~TIM_SR_UIF; // 清UIF TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开定时器, 使用非循环模式 while ((TIM1->SR & TIM_SR_UIF) == 0); // 等待UIF置位 // 返回时保留UIF=1, 下次延时时再清除 }
// 延时n微秒(0<n<65536) void delay_us(uint16_t nus) { TIM1->ARR = nus - 1; TIM1->PSC = 71; // 72MHz/72=1MHz -> 1us TIM1->EGR = TIM_EGR_UG; TIM1->SR &= ~TIM_SR_UIF; TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; while ((TIM1->SR & TIM_SR_UIF) == 0); }
// 用于延长1602液晶E信号的高电平持续时间 void delay_short(void) { uint8_t i; for (i = 0; i < 10; i++); }
void LCD1602_BusyWait(void) { RS_0; RW_1; E_1; GPIOC->CRL = 0x44444444; // 读端口 while (GPIOC->IDR & GPIO_IDR_IDR7); GPIOC->CRL = 0x33333333; E_0; }
void LCD1602_WriteCmd(uint8_t cmd) { LCD1602_BusyWait(); RS_0; RW_0; GPIOC->ODR = cmd; E_1; delay_short(); E_0; }
void LCD1602_WriteData(uint8_t data) { LCD1602_BusyWait(); RS_1; RW_0; GPIOC->ODR = data; E_1; delay_short(); E_0; }
void LCD1602_Init(void) { LCD1602_WriteCmd(0x38); LCD1602_WriteCmd(0x01); LCD1602_WriteCmd(0x0c); DAC->CR = DAC_CR_EN1 | DAC_CR_EN2; DAC->DHR8R1 = 69; // 对比度电压: 约1.0V, 端口: PA4 DAC->DHR8R2 = DAC->DHR8R1; // PA5输出同样大小的电压 }
// printf内容往液晶上显示 // 工程属性里的Use MicroLIB必须打勾 int fputc(int ch, FILE *fp) { LCD1602_WriteData(ch); return ch; }
int8_t DHT11_Read(uint8_t data[]) { uint8_t i, j; DHT11_W1; GPIOB->CRL = (GPIOB->CRL & 0xfffffff0) | 7; // 开漏输出50MHz DHT11_W0; delay_ms(18); DHT11_W1; delay_us(30); GPIOB->CRL = (GPIOB->CRL & 0xfffffff0) | 4; // 浮空输入 if (!DHT11_R) { delay_us(80); if (DHT11_R) { for (i = 0; i < 5; i++) { data[i] = 0; for (j = 0; j < 8; j++) { while (!DHT11_R); // 等待低电平 // 对高电平计时 TIM1->ARR = TIM_ARR_ARR; // 最大超时时间65.536ms TIM1->PSC = 71; TIM1->EGR = TIM_EGR_UG; // UG=1会自动将CNT清零, 但会把UIF置1 TIM1->SR &= ~TIM_SR_UIF; TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; while (DHT11_R) // 等待高电平 { if (TIM1->SR & TIM_SR_UIF) return i; // 高电平超时, 返回实际读取的数据个数 } data[i] <<= 1; if (TIM1->CNT >= 50) // CNT+1为测出的us数 data[i] |= 1; } } while (!DHT11_R); // 数据检验 if (((data[0] + data[1] + data[2] + data[3]) & 0xff) != data[4]) return -2; // 数据校验出错 return i; // 成功 } } return -1; // 传感器出错, 未读到数据 }
int main(void) { int8_t n; uint8_t data[5]; RCC->APB1ENR = RCC_APB1ENR_DACEN; RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_TIM1EN; GPIOA->CRL = 0x00000333; GPIOB->CRL = 0x00000004; GPIOC->CRL = 0x33333333; LCD1602_Init(); while (1) { LCD1602_WriteCmd(0x80); // 跳到第一行 n = DHT11_Read(data); if (n == 5 || n == -2) { // 以小数方式显示湿度(百分数*256=小数) //printf("H:%d.%02d T:%d.%02d ", data[0], MANTISSA(data[1]), (int8_t)data[2], MANTISSA(data[3])); // 以百分数方式显示湿度 printf("H:%d%% T:%d.%02d ", data[0] * 100 / 256, (int8_t)data[2], MANTISSA(data[3])); LCD1602_WriteCmd(0xc0); // 换行 printf("Sum:%d Recv:%d%c ", (data[0] + data[1] + data[2] + data[3]) & 0xff, data[4], (n == -2) ? '!' : ' '); // 感叹号表示校验错误 // 校验错误一般可忽略,因为得到的温湿度值是正确的 } else { // 读数据时出错 printf("Error! "); LCD1602_WriteCmd(0xc0); printf("n=%d ", n); } delay_ms(1000); } }
|