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 | 
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号