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