上章介绍了stm32的LED 点亮
这章在此基础上增加OLED屏显示LED灯状态)
1:环境
STM32CUBE IDE 用这个图省事(keil5也不错)
STM32F103C8T6 64KFLASH 最小核心板(10块左右)
ST-LINKV2 (5块左右) 也可以选择 JLINK(比较贵,不推荐) 安装驱动就好
STM32 ST-LINK Utility 烧录工具(单独可以BIN HEX 烧录到flash中)–可以不安装
OLED 4针脚 I2C/SPI(这里用 I2C,SPI OLED不支持),分辨率:128*64 尺寸 0.96吋
DHT11 4脚(3个脚有用 ,一个悬空) 分别接 VCC ,GND, GPIO(这里接 B0)
2:I2C协议
驱动 网上找的(4针脚)
2:配置 I2C 默认为 复用开漏输出 ,开漏输出需要外用上拉电阻,一般 5KΩ左右(一般用.4.7K Ω),没有上拉电阻,就没有高电平,屏幕一直是黑的(一度以为oled屏坏了,跑了个以前写的,屏幕亮了,看下了以前用推免输出的),修改成推免 屏幕就亮了
main.c 连同 dht11的一起粘出来了 oled.h oled.c 1306 1315的网上一堆,一般到哪里买·的,商家会提供的
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "oled.h"
#include "stdio.h"
#include "delay.h"
#include "DHT11.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/
int getth_v(uint16_t* temperature,uint16_t* humidity);
//u16 dht11_read_data_t(u8 buffer[5]);
//u16 dht11_read_byte_t(void);
//u16 dht11_read_bit_t(void);
int dth11step = 0;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
delay_init_hclk_div8();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
delay_ms_func(500); //20 ms
OLED_Init(); //初始化OLED
OLED_Clear();
// OLED_Test();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
char szbuf[16]= {0,};
char szbuft[16]= {0,};
char szbufh[16]= {0,};
uint32_t tdelay = 0 ;
uint32_t statecount = 0;
///
int num = 0 ;
uint16_t temperature=0;
uint16_t humidity=0;
int nRet = 0 ;
delay_ms_func(2000);
double hum=0.0f;
double temp=0.0f;
u8 char_size = 16 ; //16 //8
while (1)
{
/* USER CODE END WHILE */
// OLED_ShowString(0,0,"#S#",8);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);//GPIO_PIN_RESET
sprintf(szbuf,"%s(%d)","open",++statecount);
OLED_ShowString(2,0,szbuf,char_size);
delay_ms_func(2000);
///
temperature =0;
humidity =0;
dth11step = 0;
nRet= getth_v(&temperature,&humidity);
// delay_ms_t(500);
// xsprintf(szbuf,"num=%d",shownum++);
int t_temp = (int)(temperature/10) ;
sprintf(szbuft,"temp=%d",t_temp);
int t_hum = (int)(humidity/10) ;
sprintf(szbufh,"hum=%d",t_hum);
// OLED_ShowString(2,0,szbuf,16);
OLED_ShowString(2,4,szbuft,char_size);
OLED_ShowString(2,6,szbufh,char_size);
/
// delay_ms_func(2000); //18s
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);//GPIO_PIN_SET
sprintf(szbuf,"%s(%d)","close",statecount);
OLED_ShowString(2,2,szbuf,char_size);
delay_ms_func(2000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
int getth_v(uint16_t* temperature,uint16_t* humidity)
{
dht11_gpio_output();
DHT11_OUT_L; 主机将�?�线拉低(时�????>=18ms),使得DHT11能够接收到起始信号�??
// delay_us_func(20000) ;//19000HAL_Delay(19); 至少 18 ms
delay_ms_func(20);
DHT11_OUT_H; 主机将�?�线拉高,代表起始信号结束�??
delay_us_func(30); //(30) 延时20~40us
/*--------------引脚配置为输入模式,准备接收传感器回传的数据-------------------*/
dht11_gpio_input(); 配置为输入模�????
uint8_t time_cnt=0;
uint8_t i;
uint8_t bit_position;
while (dht11_scan() == RESET)
{
delay_us_func(5);
++time_cnt;
if(time_cnt > 16) return -10; //DHT11_TIMEOUT;
}
//dth11step =1;
//DHT11将�?�线拉高至少80us,为发�?�传感器数据做准备�??
time_cnt=0;
while(dht11_scan() == SET)
{
delay_us_func(5);
++time_cnt;
if(time_cnt > 16) return -11;//DHT11_TIMEOUT;
}
// dth11step =2;
/*-------------------DHT11数据帧的接收和解�????------------------*/
uint8_t DHT11_recvData_[5]={0,0,0,0,0};
for( i=0 ; i < 40 ; ++i )
{
time_cnt = 0;
while( dht11_scan() == RESET ) //拉低50us作为bit信号的起始标�????
{
time_cnt++;
delay_us_func(5);
if(time_cnt>10) return -12;//DHT11_TIMEOUT;
}
time_cnt = 0;
while( dht11_scan() == SET ) //拉高。持�????26~28us表示bit0,持�????70us表示bit1
{
time_cnt++;
delay_us_func(5);
if(time_cnt>14) return -13;//DHT11_TIMEOUT;
}
if(time_cnt>6){ //说明是bit1
bit_position = 7 - i%8;
DHT11_recvData_[i/8] |= (uint8_t)(1<<bit_position);
// dth11step += 100;
}
}
// dth11step = dth11step>=100?(100+3):3;
//------------�????验和的比�????-------------
i = (uint8_t)(DHT11_recvData_[0] + DHT11_recvData_[1] + DHT11_recvData_[2] + DHT11_recvData_[3]) ;
if(i != DHT11_recvData_[4] ) return -14;//DHT11_CHECKERROR;
// *humidity = DHT11_recvData_[0]; //回传湿度数据
// *temperature = DHT11_recvData_[2]; //回传温度数据
//放大{[10]}倍数
*humidity = (uint16_t)(DHT11_recvData_[0])*10+DHT11_recvData_[1]; //回传湿度数据
*temperature = (uint16_t)(DHT11_recvData_[2])*10+DHT11_recvData_[3]; //回传温度数据
// dth11step = DHT11_recvData_[2]>0?(1000*(int)(DHT11_recvData_[2])+dth11step):dth11step ;
return DHT11_OK;
}
/
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
说明下12864 就是 88=64 也就是8页 一个字节 8bit 64 就是8个 8bit
u8 char_size = 16 ; //16 //8 //字体为16 只有4页 为8 可以有8页
3:延时函数,延时函数不精确的话,DHT11 得不到温湿度的
为什么是200000 SysTick->LOAD 只有24bit(3BYTE 最大16777215)这里用的是最大72M
所以 1us =72 那么 tus*72 <=16777215 求得 tus = 233016.875, 这里取200000,也可以取 233016
同理 1ms =72 000 ,那么 tms 最大 取 233,取个200就可以了
大的 使用循环次数加余数 , deylay_1_us 执行时间绝对大于1us,次数多了,就不准确了
//不管是8分还是不分 都可以用 8分时,const int baseus = 200000 ; 可以*8 = 200000*8
//不分 SystemCoreClock = 72 000 000 8分时 = 9 000 000
//count_us=SystemCoreClock/1000000; //1us 多少计数
//count_ms=SystemCoreClock/1000; //1ms 多少计数
下面的不精确
// while( nus-- != 0){
// deylay_1us();//调用1微秒的延时 //每次都初始化次,执行时间大于1us,N次 可能多N/(3-10) us,
//}
void deylay_1_us(){
// 使能SysTick时钟源
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
// 设置SysTick的重载值
SysTick->LOAD = count_us - 1;
// 清除当前值
SysTick->VAL = 0;
// 使能SysTick中断和SysTick定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
// 等待SysTick定时器溢出(即延时n毫秒)
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
// // 清除溢出标志位
SysTick->CTRL |= SysTick_CTRL_COUNTFLAG_Msk;
//
// // 关闭SysTick定时器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
void deylay_n_us(uint32_t tus){
// 使能SysTick时钟源
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
// 设置SysTick的重载值
SysTick->LOAD = tus*count_us - 1;
// 清除当前值
SysTick->VAL = 0;
// 使能SysTick中断和SysTick定时器
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
// 等待SysTick定时器溢出(即延时n毫秒)
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
// // 清除溢出标志位
SysTick->CTRL |= SysTick_CTRL_COUNTFLAG_Msk;
//
// // 关闭SysTick定时器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
void delay_us_func(unsigned int nus)
{
const int baseus = 200000 ; //200000
if ( nus <= baseus) {
deylay_n_us(nus);// 72*nus <= 16777215 nus max value 233016.875
}else{
int nmul = nus/baseus ;
int remain = nus%baseus;
while(nmul-- >0){
deylay_n_us(baseus);
}
if (remain > 0){
deylay_n_us(remain);
}
//下面的不精确
// while( nus-- != 0){
//
// deylay_1us();//调用1000毫秒的延时
// }
}
参考 https://www.dfrobot.com.cn/image/data/DFR0067/DFR0067_DS_10.pdf 或取官方查找
4 运行效果
5:DEMO工程
有需要再上传(现在多加了个同时显示led灯亮灭状态),oled屏及dht11一样
如果觉得有用,麻烦点个赞,加个收藏
前期的DEMO 下载地址 dhtoledshow