(HAL库)基于STM32F103C8T6的温控PID系统[Dht11、ESP8266、无线透传、L298N……]

在参加完15届蓝桥杯嵌入式后,意犹未尽,又做了个小项目……


1.模块简介

该装置有几个部分:

1.平台搭建

2.dht11读取温湿度

3.esp8266上传阿里云

4.L298N控制舵机pid算法

电机控制部分

PID介入 

5.esp32无限透传功能

6.简单的三行代码按键和led显示

7.主函数

8.PCB制板

9.一个简单的3D制图

效果展示

接下来一块一块分开来讲


2.平台搭建

由于是基于HAL库开发,那就打开最熟悉的STM32CubeMX

引脚配置


基础部分

oled显示模块(OUTPUT)

PB6 ----------SCL

PB7----------SDA

俩按键(INPUT)

PB0----------K1

PB1----------K2

几个LED(OUTPUT)

PA5----------LD1

PA6----------LD2

控制风扇的(OUTPUT、PWM)

PA8----------ENB

PB14--------IN3

PB15--------IN4

利用TIM1产生PWM波,配置按照下图

控制加热板的(利用继电器)

PA7----------加热板+


ESP8266部分(UART)

PA3 UART2_RX

PA2 UART2_TX

其他脚按照下图接线

由于用到串口,故把串口的配置附上(利用异步时钟,波特率选择115200Bit/s,大家记得点中断!!)


无线透传部分

由于大家用的模块都不大一样,可以参考这个网站进行配置,真的大开眼界无线DAP-LINK使用指南 | 允斯工作室 (yunsi.studio)


时钟树配置


3.dht11读取温湿度

直接上代码,这一部分就是调用dht11的代码,然后在循环里调用测温度和湿度的函数即可。

dht11.c部分

#include "dht11.h"
#include "tim.h"



void DHT11_IO_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.Pin = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void DHT11_IO_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStructure);
}


//复位DHT11
void DHT11_Rst(void)	   
{                 
	DHT11_IO_OUT(); 	//设置为输出
	DHT11_DQ_OUT_LOW; 	//拉低DQ
	HAL_Delay(20);    	//拉低至少18ms
	DHT11_DQ_OUT_HIGH; 	//DQ=1 
	delay_us(30);     	//主机拉高20~40us
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void) 	   
{   
	uint8_t retry=0;
	DHT11_IO_IN();      //设置为输出	 
	while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
	while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}

//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void) 			 
{
 	uint8_t retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_DQ_IN)return 1;
	else return 0;		   
}

//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte(void)    
{        
	uint8_t i,dat;
	dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)    
{        
 	uint8_t buf[5];
	uint8_t i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=(buf[0]<<8) + buf[1];
			*temp=(buf[2]<<8) + buf[3];
		}
	}else return 1;
	return 0;	    
}

//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在     	 
uint8_t DHT11_Init(void)
{ 
  DHT11_Rst();
	return DHT11_Check();
}

dht11.h部分

#ifndef __DHT11_H__
#define __DHT11_H__

#include "main.h"

#define DHT11_DQ_OUT_HIGH HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET)
#define DHT11_DQ_OUT_LOW 	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET)

#define DHT11_DQ_IN	 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

//IO方向设置
void DS18B20_IO_IN(void);
void DS18B20_IO_OUT(void);

   	
uint8_t DHT11_Init(void);//初始化DHT11
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi);//读取温湿度
uint8_t DHT11_Read_Byte(void);//读出一个字节
uint8_t DHT11_Read_Bit(void);//读出一个位
uint8_t DHT11_Check(void);//检测是否存在DHT11
void DHT11_Rst(void);//复位DHT11  

#endif

 

4.esp8266上传阿里云

先看效果,可以在阿里云上同步观测到dht11测量到的温度和湿度

手机端也可以看到

接下来上代码,同样是.c和.h文件,主要是配置三大件有点麻烦,但不要紧只要阿里云那边的三大件都对的上,连接起来还是非常快的

.c部分

#include "esp.h"
#include "usart.h"
#include "string.h"
#include "stdio.h"
#include "dht11.h"
extern unsigned char receive_data ;   
extern uint16_t Temperature;
extern uint16_t Shidu;
extern uint8_t Lock;
extern uint8_t Switch2;
extern uint8_t string[200];
extern char RECS[250];
extern uint8_t led_status;
//const char* WIFI ="iPhone";
//const char* WIFIASSWORD="1122334455";
const char* WIFI ="202";
const char* WIFIASSWORD="ZLSYS959";
const char* ClintID="k11lrEXZkfv.temp|securemode=2\\,signmethod=hmacsha256\\,timestamp=1712202199197|";
const char* username="temp&k11lrEXZkfv";
const char* passwd="e033ec75050e41da5c29b92faa2201d6b422d63f2c464131eebaf7b9c7c21629";
const char* Url="k11lrEXZkfv.iot-as-mqtt.cn-shanghai.aliyuncs.com";
const char* pubtopic="/sys/k11lrEXZkfv/temp/thing/service/property/set";
const char* subtopic="/sys/k11lrEXZkfv/temp/thing/event/property/post";

#define SUB_TOPIC        "/sys/k11lrEXZkfv/temp/thing/service/property/set"
#define PUB_TOPIC        "/sys/k11lrEXZkfv/temp/thing/event/property/post"
//#define JSON_FORMAT      "{\\\"params\\\":{\\\"temp\\\":%d\\,\\\"humi\\\":%d\\}\\,\\\"version\\\":\\\"1.0.0\\\"}"
const char* func1="temp";
const char* func2="humi";
const char* func3="powerstate_2";
const char* func4="LEDSwitch";

//#define SUB_TOPIC        "/sys/k0zjr3AtVcM/mqtt_stm32/thing/service/property/set"
//#define PUB_TOPIC        "/sys/k0zjr3AtVcM/mqtt_stm32/thing/event/property/post"
#define JSON_FORMAT      "{\\\"params\\\":{\\\"temp\\\":%d\\,\\\"humi\\\":%d\\}\\,\\\"version\\\":\\\"1.0.0\\\"}"

char RECS[250];
unsigned char i;
char esp_Init(void)
{
	memset(RECS,0,sizeof(RECS));        
	sprintf((char *)string,"AT+RST\r\n");          //重启
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(2000);
	
	
	memset(RECS,0,sizeof(RECS));  
	sprintf((char *)string,"ATE0\r\n");          //关闭回显
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(10);
	if(strcmp(RECS,"OK"))
		return 1;

	sprintf((char *)string,"AT+CWMODE=1\r\n");     //Station模式
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(1000);
	if(strcmp(RECS,"OK"))
		return 2;


	memset(RECS,0,sizeof(RECS));
	sprintf((char *)string,"AT+CWJAP=\"%s\",\"%s\"\r\n",WIFI,WIFIASSWORD); //连接热点     //Station模式
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(2000);
	if(strcmp(RECS,"OK"))
		return 3;

	memset(RECS,0,sizeof(RECS));
	sprintf((char *)string,"AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"\r\n",ClintID,username,passwd);//用户信息配置
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(10);
	if(strcmp(RECS,"OK"))
		return 4;

	memset(RECS,0,sizeof(RECS));
	sprintf((char *)string,"AT+MQTTCONN=0,\"%s\",1883,1\r\n",Url); //连接服务器
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(1000);
	if(strcmp(RECS,"OK"))
		return 5;
	
	sprintf((char *)string,"AT+MQTTSUB=0,\"%s\",1\r\n",subtopic); //订阅消息
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
	HAL_Delay(500);
	if(strcmp(RECS,"OK"))
		return 6;
	memset(RECS,0,sizeof(RECS));
	return 0;
}
//功能:esp发送消息
//参数:无
//返回值:0:发送成功;1:发送失败
char Esp_PUB(void)
{
	memset(RECS,0,sizeof(RECS));
	//printf("AT+MQTTPUB=0,\"%s\",\"{\\\"method\\\":\\\"thing.event.property.post\\\"\\,\\\"params\\\":{\\\"%s\\\":%d\\,\\\"%s\\\":%d\\,\\\"%s\\\":%d\\,\\\"%s\\\":%d}}\",0,0\r\n",pubtopic,func1,Temperature,func2,Shidu,func3,Lock,func4,Switch2);
//	sprintf((char *)string,"AT+MQTTPUB=0,\""PUB_TOPIC"\",\""JSON_FORMAT"\",0,0\r\n",Temperature,Shidu);
	sprintf((char *)string,"AT+MQTTPUB=0,\""PUB_TOPIC"\",\""JSON_FORMAT"\",0,0\r\n",Temperature>>8,Shidu>>8); 
	HAL_UART_Transmit(&huart2, string, strlen((char *)string), 50); 
//	HAL_UART_Transmit(&huart1, string, strlen((char *)string), 50); 
//	while(RECS[0]);//等待ESP返回数据
	HAL_Delay(200);//延时等待数据接收完成
	if(strcmp(RECS,"ERROR")==0)
		return 1;
	return 0;
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART2)
    {
        RECS[i++] = receive_data;
        if((RECS[i-2] == '\r') || (RECS[i-1] == '\n'))
        {
            RECS[i-2] = '\0';
            i = 0;
            CommandAnalyse();
        }
//		 led_status^=0x01;		
	   HAL_UART_Receive_IT(&huart2, &receive_data, 1);//串口2接收1位数据
    }
}


void CommandAnalyse(void)
{
	if(strncmp(RECS,"+MQTTSUBRECV:",13)==0)
	{
		uint8_t i=0;
		while(RECS[i++] != '\0')             
		{
			if(strncmp((RECS+i),func3,9)==0)       //func3,3  数值3是func3字符串长度
			{
				while(RECS[i++] != ':');       
				Lock=RECS[i]-'0';
			}
			if(strncmp((RECS+i),func4,9)==0)
			{
				while(RECS[i++] != ':');
				led_status=RECS[i]-'0';
			}
		}
	}
}









.h部分

#include "main.h"


char esp_Init(void);
char Esp_PUB(void);
void CommandAnalyse(void);

阿里云查看三大件的方法:

 


 

5.L298N控制舵机pid算法

电机控制部分

简单来说,电机的控制就是控制它正转、反转、转的速度

正转和反转只需要让配置的引脚发出01或者10就可以正转和反转了(我用的是PB14和PB15),想让它转的快那就把PA8输出的占空比大些转的就快了,重要的PWM波生成的配置(STM32CubeMX里面的配置)

PA8----------ENB

PB14--------IN3

PB15--------IN4

那么先来看.c部分

#include "motor.h"
void Motor_Set(int Motor)
{
	TIM1->ARR=19999;
	
	//1.先根据正负设置方向GPIO 高低电平
	if(Motor <0) 
	{A_SET;B_RESET;}
	else  
	{A_RESET;B_SET;}
	
	//2.然后设置占空比  
	if(Motor <0)
	{
		if(Motor <-99) Motor =-99;
		TIM1->CCR1=20000*(-Motor)/100;
//		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (100+Motor1));
	}
	else 
	{
		if(Motor >99) Motor = 99;
		TIM1->CCR1=20000*Motor/100;
//		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,Motor1);
	}

}

.h部分

#include "main.h"
#define A_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET)
#define B_SET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET)
#define A_RESET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET)
#define B_RESET HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET)
void Motor_Set(int Motor);

PID介入 

好啦重头戏,pid算法,先上代码,其实网上的代码很多,但难的就是如何用在自己的装置上

.c部分

#include "pid.h"

//定义一个结构体类型变量
tPid pidMotor1Speed;
tPid pidT;
//给结构体类型变量赋初值
void PID_init()
{

	pidMotor1Speed.actual_val=0.0;
	pidMotor1Speed.target_val=3.00;
	pidMotor1Speed.err=0.0;
	pidMotor1Speed.err_last=0.0;
	pidMotor1Speed.err_sum=0.0;
	pidMotor1Speed.Kp=10;
	pidMotor1Speed.Ki=5;
	pidMotor1Speed.Kd=0;
	
	pidT.actual_val=0.0;
	pidT.target_val=20;
	pidT.err=0.0;
	pidT.err_last=0.0;
	pidT.err_sum=0.0;
	pidT.Kp=-30;
	pidT.Ki=0;
	pidT.Kd=0;
}
//比例p调节控制函数
float P_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//传递真实值
	pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值
	//比例控制调节   输出=Kp*当前误差
	pid->actual_val = pid->Kp*pid->err;
	return pid->actual_val;
}
//比例P 积分I 控制函数
float PI_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//传递真实值
	pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值
	pid->err_sum += pid->err;//误差累计值 = 当前误差累计和
	//使用PI控制 输出=Kp*当前误差+Ki*误差累计值
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum;
	
	return pid->actual_val;
}
// PID控制函数
float PID_realize(tPid * pid,float actual_val)
{
	pid->actual_val = actual_val;//传递真实值
	pid->err = pid->target_val - pid->actual_val;当前误差=目标值-真实值
	pid->err_sum += pid->err;//误差累计值 = 当前误差累计和
	//使用PID控制 输出 = Kp*当前误差  +  Ki*误差累计值 + Kd*(当前误差-上次误差)
	pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last);
	//保存上次误差: 这次误差赋值给上次误差
	pid->err_last = pid->err;
	
	return pid->actual_val;
}

 .h部分

#ifndef __PID_H
#define __PID_H

//声明一个结构体类型
typedef struct 
{
	float target_val;//目标值
	float actual_val;//实际值
	float err;//当前偏差
	float err_last;//上次偏差
	float err_sum;//误差累计值
	float Kp,Ki,Kd;//比例,积分,微分系数
	
} tPid;

//声明函数
float P_realize(tPid * pid,float actual_val);
void PID_init(void);
float PI_realize(tPid * pid,float actual_val);
float PID_realize(tPid * pid,float actual_val);
#endif

我来说明一下我是如何用pid使得温度恒温的。

首先我们会给一个目标值,比方说我们设定目标温度为20°C,但dht11测到的温度是28°C,那么实际与我们的设定就有8°C的偏差,那么这个8°C就会被PID算法算出来,然后我们直接把它丢到motor电机驱动的代码里,电机就会疯狂吹风(基于你给的p值(比例参数)),让它降温,直到降到目标值,是个负反馈的过程 。

最终效果就是,温度高了,风扇呼呼转,温度低了,加热板工作


6.esp32无限透传功能

无线DAP-LINK使用指南 | 允斯工作室 (yunsi.studio)

经过这个设置过后,直接就可以在keil里进行无线下载,无线是最好的电气隔离,再也不怕烧电脑主板了哈哈哈……


7.简单的三行代码按键和led显示

别问,问就是学电子设计工坊学的

.c部分

#include "main.h"
#define KB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEYPORT KB1|(KB2<<1)|0x00
unsigned char trg;
unsigned char cont;
unsigned char key_lock;
void key_read(void)
{
	unsigned char readdata=(KEYPORT)^0xff;
	if(key_lock==0)
	trg=cont&(cont^readdata);
	cont=readdata;
}

.h部分

#include "main.h"
extern unsigned char trg;
extern unsigned char cont;
extern unsigned char key_lock;
void key_read(void);


 

8.主函数

#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "led_key.h"
#include "oled.h"
#include "string.h"
#include "stdio.h"
#include "dht11.h"
#include "uart_printf.h"
#include "esp.h"
#include "core_json.h"
#include "motor.h"
#include "pid.h"

void SystemClock_Config(void);
unsigned char receive_data = 0; 
uint8_t str[21];
uint8_t string[200];
uint8_t led_status;
uint16_t Temperature;
uint16_t Shidu;
uint8_t Lock;
uint8_t Switch2;

extern tPid pidT;
//uart
unsigned char rx_buf[10],uart_buf[2];
uint16_t rx_cnt;
unsigned char rx1_buf[40];
void dht_process()
{
	DHT11_Read_Data(&Temperature,&Shidu);
}
//key
__IO uint32_t keyTick;
uint16_t key_cnt;
unsigned char desk=0;
unsigned char ld=0;
void key_process()
{
	if((uwTick - keyTick)<100)	return;//减速函数
	keyTick = uwTick;
	if(cont==0) key_lock=0;
	key_read();
		if(trg&0x01&&trg&0x02)
	{
			if(++desk==2)
			desk=0;
	}
	if(trg&0x01&&desk==1)
	{
		pidT.target_val+=0.5;
	}
	if(trg&0x02&&desk==1)
	{
		pidT.target_val-=0.5;
	}

	
}
//led
void led_process()
{
	if((int)pidT.target_val<(Temperature>>8))
	ld=1;
	else
	ld=0;
	if(ld==1)
	{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);	//加热灯
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET); //冷却灯
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET); //加热装置
//	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
	}
	else
	{
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET); //加热装置
//	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
	}
}
//MOTOR
void mot_process()
{
//	Motor_Set(0);
	Motor_Set(PID_realize(&pidT,Temperature>>8));
}
//oled
__IO uint32_t oledTick;
void oled_process()
{
	if((uwTick - oledTick)<1000)	return;//减速函数
	oledTick = uwTick;
	unsigned char buf[40];
	
	if(desk==0)
	{
	sprintf((char *)buf,"     <DHT11>   ");
	OLED_ShowString(0,0,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
	
	sprintf((char *)buf,"    T:%d.%d C  ",Temperature>>8,Temperature&0xff);
	OLED_ShowString(0,3,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
 
	sprintf((char *)buf,"    H:%d.%d %%     ",Shidu>>8,Shidu&0xff);
	OLED_ShowString(0,5,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
	}
	if(desk==1)
	{
	sprintf((char *)buf,"    <MOTOR+T> ");
	OLED_ShowString(0,0,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
		
	sprintf((char *)buf,"    NOW:%d.%d C  ",Temperature>>8,Temperature&0xff);
	OLED_ShowString(0,3,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
		
	sprintf((char *)buf,"    SET:%.1f C  ",pidT.target_val);
	OLED_ShowString(0,5,buf,16);//这个是oled驱动里面的,是显示位置的一个函数,
	}

		if(Esp_PUB() == 1)
	{
		OLED_ShowString(1,1,"publish failed",16);
		HAL_Delay(500);
		OLED_Clear();
	}
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM3_Init();
  MX_TIM1_Init();

  	OLED_Init();			//初始化OLED  
	OLED_Clear(); 
	uint8_t Judge=0;	
	OLED_ShowString(1,3," Linking...",16);  

	HAL_UART_Receive_IT(&huart2,uart_buf, 1);
	do
	{
		Judge = esp_Init();
		sprintf((char *)str,"error code:%d",Judge);  
	  OLED_ShowString(0,2,str,16);
	}
	while(Judge);  //连接阿里云直到成功
	sprintf((char *)str, "Ali-Cloud OK!");
	OLED_ShowString(0,0,str,16);
	HAL_Delay(500);
	OLED_Clear(); 
	HAL_TIM_PWM_Start_IT(&htim1,TIM_CHANNEL_1);
	PID_init();
  while (1)
  {
	oled_process();
	dht_process();
	key_process();
	led_process();
	mot_process();
  }
}


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

void Error_Handler(void)
{
  
  __disable_irq();
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line)
{

}
#endif

 

9.PCB制板

白嫖嘉立创嘿嘿……

直接上文件

控制电机的引脚直接从底部出来,好走线


 

10.一个简单的3D制图

一个门外汉随便画着玩的,为了给dht11一个家,想到它的功能可以测温度和湿度,就想到百叶箱,就给它用soildwork建了个模型

效果如下:

效果展示

  • 55
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值