Article directory
overall block diagram
Software: keil5, STM32Cubemx
Hardware: Taobao's STM32F103C8T6 minimum system
1. Basic engineering
1 new construction
2 Configure RCC
Select external clock source.
Set the input value of the external crystal oscillator, my board is 8M.
Then manually enter the maximum clock frequency, and press Enter to let him automatically configure the clock tree. My board is 72M.
3 Configure SYS
My downloader is SWD two wires, so I choose this. (Be sure to configure the download mode before downloading the program, otherwise the MCU will be bricked and needs to be downloaded from the serial port for recovery)
4 Project settings
5 Generate code
Click to generate code
Open the keil project
6 Keil settings download & reset
Select the downloader type, I use DAP. Click on the following Settings.
After entering, check the automatic reset, which means that the single-chip microcomputer will automatically reset and run the program after each program download.
Click OK after setting.
2. Necessary peripherals
1 Directory specification
Under the project directory, create a new ICODE folder to store various peripheral files written by yourself.
2 LED
1 Import the .ch file (that is, import the .ch file into the keil project, and this link will not be described later)
Copy the previously written LED folder to the ICODE directory of this project.
There are led.c led.h folder inside.
In the project, create the ICODE folder and add the led.c file.
In the project, add the led.h file.
2 Cubemx configuration
Configure the board LED pins, push-pull output mode. My board is PC13.
Regenerate the code.
3 Modify the .h file
To change to other pins, just change the LED port number and pin PIN. My board is PC13.
4 tests
Add #include "led.h" in main.c
and add the following code in while. LED light blinks.
LED_Contrary();
HAL_Delay(500);//500ms
2 RTC
1 Import the .ch file (no more details, see the LED section for details)
none
2 Cubemx configuration
Conflict with PC13, the core board PC13 is an LED, so disable RTC OUT.
3 Modify the .c file
In the interrupt.c, add the led header file, and in the RTC interrupt function, add the 500ms, LED level inversion function.
#include "led.h"
static uint16_t rtccnt=0;
rtccnt++;
if(rtccnt>500) rtccnt=0,LED_Contrary();
4 tests
The LEDs blink.
3 USE
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
Tick to use
2 Cubemx configuration
Use serial port 1, default baud rate, asynchronous communication.
enable interrupt
3 Modify the .h file
The code uses serial port 1 by default. Adding other serial ports can be done in .h, copied and renamed.
4 tests
Serial send/receive function:
HAL_UART_Transmit();串口发送数据,使用超时管理机制
HAL_UART_Receive();串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT();串口中断模式发送
HAL_UART_Receive_IT();串口中断模式接收
HAL_UART_Transmit_DMA();串口DMA模式发送
HAL_UART_Transmit_DMA();串口DMA模式接收
Serial interrupt function:
HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //串口发送中断回调函数
HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //串口发送一半中断回调函数(用的较少)
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //串口接收中断回调函数
HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(用的较少)
HAL_UART_ErrorCallback();串口接收错误函数
The commonly used sending function is: HAL_UART_Transmit();
The commonly used receiving function is: HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
HAL library serial port interrupt call process:
send:
1 printf remapping:
/* printf重映射 */
#include <stdio.h>
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
//具体哪个串口可以更改huart1为其它串口
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1 , 0xffff);
return ch;
}
2 printf sends:
printf("hello \r\n"); //发送字符串
float Data=1.11;
printf("Data=%.2f \r\n",Data); //发送变量
3 Hal library comes with sending function:
#include <stdio.h>
HAL_UART_Transmit(&huart1,"hello\r\n",sizeof("hello\r\n"),0xffff);//发送字符串
uint8_t Data1[]={
"hello\r\n"};
HAL_UART_Transmit(&huart1,Data1,sizeof(Data1),0xffff);//发送字符串
uint8_t Databuffer[20]={
0};
float Data=1.11;
sprintf(Databuffer,"Data=%.2f \r\n",Data);
HAL_UART_Transmit(&huart1,Databuffer,strlen(Databuffer),0xffff);//发送变量 用strlen
Interrupt reception:
1 fixed length
/*
串口接收中断
定长接收
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart1)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&Uart1_RxData,1,0xffff);//原样返回
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
HAL_UART_Receive_IT(&huart1,(uint8_t *)&Uart1_RxData, 1); //&取地址
}
}
2 variable length
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
if(huart == &huart1)
{
if(Uart1_Rx_Cnt >= 255) //溢出判断
{
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuffer,0x00,sizeof(Uart1_RxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);
}
else
{
Uart1_RxBuffer[Uart1_Rx_Cnt++] = Uart1_RxData; //接收数据转存
if((Uart1_RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位\r\n。0x0D是\r,0x0A是\n
{
/* 此处添加用户代码 */
HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
/* 此处添加用户代码 */
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuffer,0x00,sizeof(Uart1_RxBuffer)); //清空数组
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&Uart1_RxData, 1); //再开启接收中断
}
}
4 KEY
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
3 Modify the .h file
4 tests
3. Other peripherals
1 OLED (analog IIC, analog SPI)
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project. Choose IIC or SPI. (analog IIC and analog SPI)
2 Cubemx configuration
Choose the GPIO corresponding to the number of OLED pins and set it as push-pull output. Set to high speed.
3 Modify the .h file
To change to other pins, just change OLED port number and pin PIN
4 tests
OLED display font size 16*16 is the most suitable. Can put 4 lines: 0 16 32 48.
add header file
#include "oled.h"
add initialization
OLED_Init();
OLED_ColorTurn(0); //0正常显示,1 反色显示
OLED_DisplayTurn(0); //0正常显示 1 屏幕翻转显示
1 Display characters:
OLED_ShowString(0,0,"hello",16,1);
OLED_Refresh();//更新0
2 Display variables:
uint8_t Databuffer[20]={
0};
float Data=1.11;
sprintf(Databuffer,"Data=%.2f \r\n",Data);//sprintf
OLED_ShowString(0,16,Databuffer,16,1);
OLED_Refresh();
3 Display Chinese:
2 BH1750 light intensity detection
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
3 Modify the .h file
4 tests
add header file
add initialization
3 MQ2 smoke detection
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
Pick an ADC pin at will. Initialize ADC pins.
3 Modify the .h file
4 tests
add header file
#include "mq2.h"
collection
uint16_t MQ2_DATA=0;
MQ2_DATA = GetMQ4Value();
3 MQ4 formaldehyde detection
Same as MQ2, read AD.
Concentration conversion function:
uint16_t GetMQ4Value(void)
{
uint16_t ADCVal;
float Voltage;
uint16_t ppm;
HAL_ADC_Start(&hadc1);//开始ADC采集
HAL_ADC_PollForConversion(&hadc1,500);//等待采集结束
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位
{
ADCVal = HAL_ADC_GetValue(&hadc1);//读出ADC数值
}
Voltage = ADCVal * 3.3 / 4096;
//无天然气的环境下,实测AOUT端的电压为0.5V,当检测到天然气时,电压每升高0.1V,实际被测气体浓度增加200ppm
ppm = (Voltage - 0.5) / 0.1 * 200;
return ppm;
//return ADCVal;
}
4 DHT11 temperature and humidity
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-4kFUCvSv-1681004471418)(null)]
2 Cubemx configuration
Choose an IO port and configure it as high-speed, push-pull output.
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
Choose an IO port at will. Configured as a push-pull output, high speed.
3 Modify the .h file
To define the GPIO port connected to the DHT11 bus, you only need to modify the following 2 lines of code to change the DATA pin arbitrarily
4 tests
add header file
#include "dht11.h"
add initialization
DHT11_Init(); //DHT11温湿模块初始化
read temperature and humidity
uint8_t DHT11_DATA[2]={0}; //用于存放DHT11温湿度数据
DHT11_ReadData(DHT11_BUF); //读出DHT11传感器数据(参数是存放数据的数组指针)
printf("湿度:%2d% 温度:%2d℃\r\n",DHT11_BUF[0],DHT11_BUF[1]);//串口打印湿度温度
5 SIM900A GSM module
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
3 Modify the .h file
4 tests
add header file
add initialization
6 BMP180 air pressure sensor
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
Using analog IIC, choose any two io ports to set as push-pull output mode. I choose B7 B6 here.
Configure serial port 1 and remap printf.
Cubemx basic project and configuration see: [HAL library] HAL library STM32cubemx quick use
3 Modify the .h file
You only need to modify the following 2 lines of code to change the pins arbitrarily
4 tests
add header file
#include "bmp1801.h"
add initialization
BMP_Init(); //BMP180初始化
BMP_ReadCalibrationData();//BMP180初始化
read
uint8_t ID = 0; //BMP180器件号
ID = BMP_ReadOneByte(0xd0); //读取设备ID
BMP_UncompemstatedToTrue(); //读取气压值
printf("ID = %d\t temp = %d.%dC\t Pressure = %.2fkPa\t Altitude = %.5fm\r\n",ID,bmp180.Temp/10,bmp180.Temp%10,(float)bmp180.p/1000.0,bmp180.altitude);
HAL_Delay(500);
7 ESP8266+Onenet+HTTP
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
3 Modify the .h file
4 tests
add header file
add initialization
8 ESP8266+Onenet+MQTT
1 Import the .ch file (no more details, see the LED section for details)
Import the previously written .ch file into the keil project.
2 Cubemx configuration
Serial port 1 is used for debugging, serial port 3 is used for ESP8266 communication, and the interrupt is enabled.
I will not configure the basic ones, you can see the detailed explanation above.
3 Modify the .ch file
Things to modify when transplanting:
1 Change the serial port used
Sending part: In esp8266.c, replace all huart3 with the serial port number to be modified, such as serial port 2.
Receiving part: Use the serial port interrupt to receive the message from esp8266. Add the serial port callback function in any folder. I personally created a uart.c file to put all the codes related to the serial port.
Add the following code (serial port number is modified according to personal circumstances)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &huart3)//esp8266接收云平台数据
{
if(esp8266_cnt >= sizeof(esp8266_buf))
{
esp8266_cnt = 0; //防止串口被刷爆
}
esp8266_buf[esp8266_cnt++] = Uart3_RxData;
HAL_UART_Receive_IT(&huart3,(uint8_t *)&Uart3_RxData, 1); //&取地址
}
}
2 Change wifi name and password
3 Change the product ID, device ID, and authentication information.
4 tests
add header file
#include "onenet.h"
#include "esp8266.h"
add initialization
Don't forget to open the serial interrupt.
HAL_UART_Receive_IT(&huart3,(uint8_t *)&Uart3_RxData, 1);//开启串口中断
/* esp8266连接wifi+连接Onenet */
HAL_Delay(2000);
ESP8266_Init(); //初始化ESP8266,连接wifi
HAL_Delay(2000);
while(OneNet_DevLink()) //连接OneNET
HAL_Delay(2000);
If the connection is successful, onenet will display that the device is online. The serial port will also print successfully.
send data
OneNet_SendData(); //发送数据
ESP8266_Clear(); //清空数据缓存区
HAL_Delay(3000); //3s发送一次
What data to send, change here:
Receive data
dataPtr = ESP8266_GetIPD(0);//获取平台返回的数据
if(dataPtr != NULL)//如果返回数据不为空
OneNet_RevPro(dataPtr);//平台返回数据检测