stm32笔记[15]-蓝桥物联网笔记整理
摘要
整理蓝桥杯物联网必背笔记.
关键信息
- Keil 5.35.00
- HAL库版本:STM32Cube FW_L0 V1.12.0
- STM32CubeMX:6.2.1
- 芯片:STM32L071KBU
快速开始 | FASTBOOT
准备工作
- STM32CubeMX新建工程
- 选择STM32L071KBU芯片
- 配置引脚
- OLED_SCL:PA8(I2C3_SCL)
- OLED_SDA:PB4(I2C3_SDA)
- OLED_PWR:PB5(低电平有效,GPIO_OUTPUT)
- RELAY_K1:PA11(高电平有效)
- RELAY_K2:PA12(高电平有效)
- LORA_INT:PA10(GPIO_OUTPUT,高电平有效)
- LORA_RST:PA9(GPIO_OUTPUT,高电平有效)
- LORA_CS:PA4(SPI1)
- LORA_CLK:PA5(SPI1)
- LORA_MISO:PA6(SPI1)
- LORA_MOSI:PA7(SPI1)
- GENERAL1:PB0
- GENERAL2:PB1
- GENERAL3:PB4
- GENERAL4:PA8
- GENERAL5:PB6
- GENERAL6:PB7
- LED_LD5:PC15(低电平有效,GPIO_OUTPUT)
- KEY_USER:PC14(GPIO_INPUT)
- 打开功能
- I2C
- SPI
- USART2
- TIM6
- 配置HCLK为32MHz,然后自动生成解决方案
- 打开Keil工程
- 测试编译
- 配置调试器为CMSIS-DAP
- 标记工程为NODE_A,复制工程为NODE_B
做题流程
- 测试LoRa通信及指示灯
- 测试OLED显示
- 测试按键
- 测试串口
- 测试ADC
模块驱动
目录
- 串口收发驱动(中断方式)
- LoRa收发驱动
- OLED显示驱动
- LED指示灯驱动
- ADC驱动
- 继电器驱动
- 矩阵键盘驱动
- 定时器驱动
- 温度传感器驱动
- 脉冲测量驱动
- EEPROM读写驱动
- 光敏与红外热释电驱动
- 按键(消抖)驱动
串口收发驱动
main.h
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
// 定义共享全局变量
extern char g_frame_buffer[32];
extern int g_frame_buffer_pos;
/* USER CODE END ET */
main.c
/* USER CODE BEGIN PV */
char g_frame_buffer[32];
int g_frame_buffer_pos;
/* USER CODE END PV */
static void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART1;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
// 添加空闲中断
HAL_NVIC_EnableIRQ(USART2_IRQn);
HAL_NVIC_SetPriority(USART2_IRQn,3,3);
// 允许中断标志位
__HAL_UART_ENABLE_IT(&huart2,UART_IT_RXNE);//接收中断
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);//空闲中断
/* USER CODE END USART2_Init 2 */
}
stm32l0xx_it.c
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
// 串口接收到字符会自动调用HAL_UART_RxCpltCallback()
uint8_t rec; // 暂存接收到的数据
// 接收中断
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET) {
HAL_UART_Receive(&huart2, &rec, 1, 1000);
if (g_frame_buffer_pos < 256) { // 确保不会溢出
g_frame_buffer[g_frame_buffer_pos++] = rec; // 存储数据并更新长度
}
// 清除中断接收标志
__HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_RXNE);
}
// 空闲中断
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET){
// 接收完成一帧数据
while(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_TC) != SET);
// 清除中断接收标志
__HAL_UART_CLEAR_FLAG(&huart2,UART_FLAG_IDLE);
// 调试:转发数据
HAL_UART_Transmit(&huart2,"Idle_Rec:",9,1000);
HAL_UART_Transmit(&huart2,(uint8_t*)g_frame_buffer,g_frame_buffer_pos,1000);
HAL_UART_Transmit(&huart2,"\n",2,1000);
// TODO 处理接收数据
// 清除接收数据
memcpy(g_frame_buffer,0x0,sizeof(g_frame_buffer));
g_frame_buffer_pos = 0;
}
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
LoRa收发驱动(硬件SPI)
对LoRa模块的操作通过SPI接口实现。
lora.c文件中提供SPI_WriteRead接口函数。
选手需要通过STM32 Cube MX配置硬件SPI接口工作模式,或使用GPIO模拟实现SPI总线时序,完成SPI_WriteRead接口函数功能。
- 使用资源包->参考代码内的lora.c,lora.h和spi.h文件.复制文件到main.c文件同目录,keil中添加文件.
- 配置PA5,PA6,PA7为SPI相关
- 配置PA4为GPIO_OUTPUT
- 互相传数据不要用memcpy,直接用数组赋值的形式传递数据
main.h
/* USER CODE BEGIN EFP */
extern SPI_HandleTypeDef hspi1;
/* USER CODE END EFP */
lora.c
#include "spi.h"
#include "main.h"
uint8_t SPI_WriteRead(uint8_t Addr,uint8_t Data){
uint8_t pTx[2]={Addr,Data};
uint8_t pRx[2];
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1,pTx,pRx,2,10);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
return pRx[1];
}
void LORA_Init(void)
{
// 使能射频芯片
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
// SPI_WriteRead(0x81, 0); ...
}
main.c
/* USER CODE BEGIN Includes */
#include "lora.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
// LORA初始化
LORA_Init();
/* USER CODE END 2 */
// LoRa发送
uint8_t g_lora_tx_buf[23]; // lora发送缓存
g_lora_tx_buf[0]='A';
g_lora_tx_buf[1]=g_time.Hours;
g_lora_tx_buf[2]=g_time.Mins;
g_lora_tx_buf[3]=g_time.secs;
g_lora_tx_buf[4]='c';
g_lora_tx_buf[5]='d';
LORA_Tx(g_lora_tx_buf,6);
// LoRa接收
uint8_t g_lora_rx_buf[23]; // lora接收缓存
void fn_lora_rx_handler(void){
unsigned char s_length = LORA_Rx((unsigned char*)g_lora_rx_buf);
if(g_lora_rx_buf[0] != '\0'){
HAL_UART_Transmit(&huart2,g_lora_rx_buf,16,160);
}
if(g_lora_rx_buf[0]=='A'){
OLED_ShowString(28,2,(uint8_t *)"hihi",16);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET);
}
}
while(1){
fn_lora_rx_handler();
}
OLED显示驱动(硬件I2C)
对OLED屏幕的操作通过I2C接口实现。
oled.c文件中提供OLED_Write接口函数。
选手需要通过STM32 Cube MX配置硬件I2C接口工作模式,或使用GPIO模拟实现I2C总线时序,完成OLED_Write接口函数功能。
- 使用资源包->参考代码内的oled.c,oled.h,font.h和i2c.h文件.复制文件到main.c文件同目录,keil中添加文件.
i2c.h
/* USER CODE BEGIN Prototypes */
extern I2C_HandleTypeDef hi2c3;
/* USER CODE END Prototypes */
oled.c
void OLED_Write(uint8_t type,uint8_t data)
{
uint8_t pTx[2]={type,data};
HAL_I2C_Master_Transmit(&hi2c3,0x78,pTx,2,10);
}
main.c
/* USER CODE BEGIN Includes */
#include "oled.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
struct Time{
uint8_t Hours;
uint8_t Mins;
uint8_t secs;
uint8_t Subsecs;
}g_time={23,59,55}; // 时间
uint8_t g_oled_buf[17]; // 显示屏缓存区
/* USER CODE END 0 */
/* USER CODE BEGIN I2C3_Init 2 */
HAL_Delay(100); // 延时以初始化完成
/* USER CODE END I2C3_Init 2 */
/* USER CODE BEGIN 2 */
// OLED初始化
OLED_Init();
sprintf((char*)g_oled_buf,"%02d:%02d:%02d",g_time.Hours,g_time.Mins,g_time.secs);
OLED_ShowString(24,0,g_oled_buf,16);
/* USER CODE END 2 */
ADC驱动
- 如果使用Pot&LED模块则配置RP1:PB1:ADC_IN9,RP2:PB0:ADC_IN8
- 如果使用ADC&PULSE模块则配置PR1:PB1:ADC_IN9,PR2:PB0:TIM3_CH3
- 配置允许ADC连续转换
main.c
// 读取ADC的值
void adcHandler(void){
HAL_ADC_Start(&hadc); // 启动ADC
// 读取ADC通道8的值
hadc.Instance->CHSELR = ADC_CHANNEL_8;
HAL_ADC_PollForConversion(&hadc, 100); // 等待转换完成
uint16_t adc_value_chan8 = HAL_ADC_GetValue(&hadc); // 获取通道8的值
// 计算通道8的整数和小数部分
// 假设ADC的参考电压是3.3V,12位ADC的分辨率是3.3V / 4096
g_adc_value.rp2_1 = adc_value_chan8 * 3300 / 4096 / 1000; // 整数部分
g_adc_value.rp2_2 = (adc_value_chan8 - g_adc_value.rp2_1) / 1000; // 小数部分
// 读取ADC通道9的值
hadc.Instance->CHSELR = ADC_CHANNEL_9;
HAL_ADC_PollForConversion(&hadc, 100); // 等待转换完成
uint16_t adc_value_chan9 = HAL_ADC_GetValue(&hadc); // 获取通道9的值
// 计算通道9的整数和小数部分
// 假设ADC的参考电压是3.3V,12位ADC的分辨率是3.3V / 4096
g_adc_value.rp1_1 = adc_value_chan9 * 3300 / 4096 / 1000; // 整数部分
g_adc_value.rp1_2 = (adc_value_chan9 - g_adc_value.rp1_1) / 1000; // 小数部分
}
继电器驱动
main.c
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET); // 使能K1继电器
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET); // 使能K2继电器
矩阵键盘驱动
main.c
/*
重新初始化矩阵键盘的引脚
re init keypad gpio
reuse gpio
COL(PB1,PB0,PA8)OUTPUT,
ROW(PB6,PB7)INPUT
*/
void keypadInit(void){
HAL_I2C_MspDeInit(&hi2c3);
GPIO_InitTypeDef GPIO_InitStruct = {0};
// PB6,PB7->INPUT
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// PB1,PB0,PA8->OUTPUT
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/*
扫描矩阵键盘
scan keypad
COL(PB1,PB0,PA8)OUTPUT,
ROW(PB6,PB7)INPUT
*/
uint8_t keypadScan(void){
#define COL3_GPIO_Port GPIOA
#define COL3_Pin GPIO_PIN_8
#define COL2_Pin GPIO_PIN_0
#define COL2_GPIO_Port GPIOB
#define COL1_Pin GPIO_PIN_1
#define COL1_GPIO_Port GPIOB
#define ROW1_Pin GPIO_PIN_6
#define ROW1_GPIO_Port GPIOB
#define ROW2_Pin GPIO_PIN_7
#define ROW2_GPIO_Port GPIOB
uint16_t ROW[2]={ROW1_Pin,ROW2_Pin};
uint16_t COL[3]={COL1_Pin,COL2_Pin,COL3_Pin};
uint8_t s_keypad_name[3][2]={{'1','4'},{'2','5'},{'3','6'}};
// g_keypad_pressed
uint8_t s_col_index = 0;
uint8_t s_row_index = 0;
uint8_t s_keypad_pressed = 0;
// set col gpio status
HAL_GPIO_WritePin(COL1_GPIO_Port,COL1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(COL2_GPIO_Port,COL2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(COL3_GPIO_Port,COL3_Pin,GPIO_PIN_SET);
for(s_col_index = 0 ; s_col_index < 3 ; s_col_index ++){
if(s_col_index != 2) {HAL_GPIO_WritePin(GPIOB,COL[s_col_index],GPIO_PIN_RESET); }
else {HAL_GPIO_WritePin(COL3_GPIO_Port,COL[2],GPIO_PIN_RESET); }
for(s_row_index = 0; s_row_index < 2 ; s_row_index ++){
if(HAL_GPIO_ReadPin(GPIOB,ROW[s_row_index]) != GPIO_PIN_SET){
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOB,ROW[s_row_index]) != GPIO_PIN_SET){
g_keypad_pressed = s_keypad_name[s_col_index][s_row_index];
s_keypad_pressed = s_keypad_name[s_col_index][s_row_index];
while(HAL_GPIO_ReadPin(GPIOB,ROW[s_row_index]) == GPIO_PIN_SET);
// blink
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
return s_keypad_pressed;
} // end if
} // end if
} // end for row
} // end for col
return s_keypad_pressed;
}// end function
/*
重新初始化显示屏的引脚
re init display gpio
reuse gpio
*/
void displayInit(void){
HAL_I2C_MspInit(&hi2c3);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
MX_I2C3_Init();
sprintf((char*)g_oled_buf,"key:%c",g_keypad_pressed);
OLED_ShowString(24,2,g_oled_buf,16);
}
定时器(及中断)驱动
main.c
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6); // 使能TIM6
/* USER CODE END 2 */
/* TIM6 init function */
void MX_TIM6_Init(void){
/* USER CODE BEGIN TIM6_Init 0 */
/* USER CODE END TIM6_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */
// 定时1s一次中断,sysclk=32MHz
htim6.Instance = TIM6;
htim6.Init.Prescaler = 32000-1;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 1000-1;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM6_Init 2 */
/* USER CODE END TIM6_Init 2 */
}
// 中断处理函数
void TIM6_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_IRQn 0 */
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
/* USER CODE END TIM6_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_IRQn 1 */
/* USER CODE END TIM6_IRQn 1 */
}
温度传感器驱动
main.c
float Mycode_SHS30(void)
{
unsigned char data[2];
data[0] = 0x24; // 不使能时钟伸缩
data[1] = 0x0B; // 中重复性测量精度
// 0x94是通过0x4A向左移一位得来的,0表示写1表示读,这里最低位为0(0X4A为STS30地址)
HAL_I2C_Master_Transmit(&hi2c1, 0x94, data, 2, 10);
HAL_Delay(10);
// 0x94是通过0x4A向左移一位再加一得来的,0表示写1表示读,这里最低位为1(0X4A为STS30地址)
HAL_I2C_Master_Receive(&hi2c1, 0x95, data, 2, 10);
return (float)(-45)+175*(data[0]<<8|data[1])/65535;
}
脉冲测量驱动
main.c
static void MX_TIM3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*##-1- 使能总线和GPIO时钟
#################################*/
/* TIMx Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* Enable GPIO channels Clock */
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Configure (TIMx_Channel) in Alternate function, push-pull and high speed */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*##-2- 配置TIMx的中断控制器
#########################################*/
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);
/* Enable the TIMx global Interrupt */
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TimHandle.Instance = TIM3;
/* Initialize TIMx peripheral as follows:
+ Period = 0xFFFF
+ Prescaler = 0
+ ClockDivision = 0
+ Counter direction = Up
*/
TimHandle.Init.Period = 0xFFFF;
TimHandle.Init.Prescaler = 0;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_IC_Init(&TimHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-3- 配置脉冲输入引脚
################################*/
/* Configure the Input Capture of channel 3 */
sICConfig.ICPolarity = TIM_ICPOLARITY_RISING;
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI;
sICConfig.ICPrescaler = TIM_ICPSC_DIV1;
sICConfig.ICFilter = 0;
if(HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIM_CHANNEL_3) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
/*##-4- 开始中断触发方式捕获
##########################*/
if(HAL_TIM_IC_Start_IT(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
{
/* Starting Error */
Error_Handler();
}
}
// 脉冲捕获中断回调
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(uhCaptureIndex == 0)
{
uwIC2Value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
uhCaptureIndex = 1;
}
else if(uhCaptureIndex == 1)
{
uwIC2Value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
if (uwIC2Value2 > uwIC2Value1)
{
uwDiffCapture = (uwIC2Value2 - uwIC2Value1);
}
else if (uwIC2Value2 < uwIC2Value1)
{
uwDiffCapture = ((0xFFFF - uwIC2Value1) + uwIC2Value2) + 1;
}
else
{
Error_Handler();
}
uwFrequency = HAL_RCC_GetPCLK1Freq() / uwDiffCapture;
uhCaptureIndex = 0;
}
}
}
EEPROM读写驱动
eeprom.h
#ifndef __EEPROM_H
#define __EEPROM_H
#include "main.h"
//MAX_3KB
#define MCU_Start_Address_Bank1 0x08080000
//MAX_3KB
#define MCU_Start_Address_Bank2 0x08080C00
void flashWrite(uint32_t address,uint8_t *data,uint8_t length);
void flashRead(uint32_t address,uint8_t *data,uint8_t length);
#endif
#include "eeprom.h"
//MAX 3KB
void flashWrite(uint32_t address,uint8_t *data,uint8_t length){
HAL_FLASHEx_DATAEEPROM_Unlock();// 解锁Flash
for(uint8_t i=0;i< length;i++){
*(__IO uint8_t *)address = (uint8_t) data[i];
address+=1;
}
HAL_FLASHEx_DATAEEPROM_Lock();// 上锁Flash
}
//MAX 3KB
void flashRead(uint32_t address,uint8_t *data,uint8_t length){
for(uint8_t i=0;i< length;i++){
data[i]=*(__IO uint8_t *)address;
address+=1;
}
}
// 读写EEPROM
flashWrite(MCU_Start_Address_Bank1,"hello",strlen("hello"));
uint8_t test_eeprom[strlen("hello")];
flashRead(MCU_Start_Address_Bank1,test_eeprom,strlen("hello"));
unsigned char b2[16];
sprintf((char*)b2, "r:%s",test_eeprom);
OLED_ShowString(5, 2, b2, 16);
光敏与红外热释电驱动
uint16_t usAdc[2];
ADC_Read(usAdc);
sprintf((char*)ucBuf, " %04u %4.2fV", usAdc[1], usAdc[1]*3.3/4095);
OLED_ShowString(0, 0, " RES - PHOTO", 16);
OLED_ShowString(0, 2, ucBuf, 16);
// 红外热释电传感器
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_SET){
// 高电平有效,有感应到红外物体
}else{
// 没有红外物体
}
// 读取光敏传感器
void ADC_Read(uint16_t *usData){
// ADC1
HAL_ADC_Start(&hadc);
if(HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)
usData[0] = HAL_ADC_GetValue(&hadc);
if(HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)
usData[1] = HAL_ADC_GetValue(&hadc);
}
/* USER CODE BEGIN ADC_Init 2 */
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
/* USER CODE END ADC_Init 2 */
按键(消抖)驱动
main.c
// 扫描按键
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14) == GPIO_PIN_RESET){
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14) == GPIO_PIN_RESET){
// TODO 执行按键功能
}
}
常用程序
目录
- 字符串/字符查找
- 串口打印封装
- 内存映射/拷贝
- 数据类型转换
字符串/字符查找
- strstr,memchr
char * strstr ( const char *str1, const char * str2);
字符串分割
- strtok
char * strtok ( char * str, const char * sep );
串口打印封装
//串口打印函数
void uart1_printf(char * input){
char b2[32];
snprintf(b2, sizeof(b2), "log:%s\n", input);
HAL_UART_Transmit(&huart1, (uint8_t *)b2, strlen(b2), strlen(b2) * 10);
}
内存映射/拷贝
- mmap
- memcpy
- memmove
- memcmp
- memset
mmap()函数的主要用途有三个:
- 将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能,
- 将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间,
- 为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。
#include <sys/mman.h>
void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
void * memcpy ( void * dest, const void * src, size_t count);
void * memmove ( void * dest, const void * src, size_t count );
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
void* memset( void * dest, int c, size_t count);
数据类型转换
double atof (const char* str);
float strtof (const char* str, char** endptr);
double strtod (const char* str, char** endptr);
long double strtold (const char* str, char** endptr);
模块引脚表格
引脚编号 | 功能 | 引脚功能 | 资源复用 | EX1模块(键盘) | EX2模块(ADC采集) | EX3模块(温湿度) | EX4模块(脉冲输出) | EX5模块(光敏、热释电) |
---|---|---|---|---|---|---|---|---|
PIN1 | 5V | 5V电源 | N/A | NC | NC | NC | NC | NC |
PIN2 | PB6 | USART1_TX/I2C1_SCL/LPTIM1_ETR/COMP2_INP | N/A | ROW1 | LD1 | SCL(STS30) | LED2 | DO(AS312) |
PIN3 | GND | 地 | N/A | GND | GND | GND | GND | GND |
PIN4 | PB7 | USART1_RX/I2C1_SDA/LPTIM1_IN2/USART4_CTS/COMP2_INP/VREF_PVD_IN | N/A | ROW2 | LD2 | SDA(STS30) | LED1 | NC |
PIN5 | PB1 | TIM3_CH4/LPUART1_RTS/LPUART1_DE/ADC_IN9/VREF_OUT | N/A | COLUMN1 | AIN(RP1) | NC | AIN(RP1) | AIN(光敏) |
PIN6 | GND | 地 | N/A | GND | GND | GND | NC | GND |
PIN7 | PB0 | EVENTOUT/TIM3_CH3/ADC_IN8/VREF_OUT | N/A | COLUMN2 | AIN2(RP2) | ALE(STS30) | PULS(RP3) | NC |
PIN8 | PA8 | MCO/EVENTOUT/USART1_CK/I2C3_SCL | OLED_SCL | COLUMN3 | NC | NC | NC | NC |
PIN9 | 3.3V | 3.3V电源 | N/A | NC | 3.3V电源 | 3.3V电源 | 3.3V电源 | 3.3V电源 |
PIN10 | PB4 | SPI1_MISO/TIM3_CH1/TIM22_CH1/USART1_CTS/USART5_RX/I2C3_SDA/COMP2_INP | OLED_SDA | NC | NC | NC | NC | NC |