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