stm32笔记[15]-蓝桥物联网笔记整理

摘要

整理蓝桥杯物联网必背笔记.

关键信息

  • Keil 5.35.00
  • HAL库版本:STM32Cube FW_L0 V1.12.0
  • STM32CubeMX:6.2.1
  • 芯片:STM32L071KBU

快速开始 | FASTBOOT

准备工作

  1. STM32CubeMX新建工程
  2. 选择STM32L071KBU芯片
  3. 配置引脚
  • 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)
  1. 打开功能
  • I2C
  • SPI
  • USART2
  • TIM6
  1. 配置HCLK为32MHz,然后自动生成解决方案
  2. 打开Keil工程
  3. 测试编译
  4. 配置调试器为CMSIS-DAP
  5. 标记工程为NODE_A,复制工程为NODE_B

做题流程

  1. 测试LoRa通信及指示灯
  2. 测试OLED显示
  3. 测试按键
  4. 测试串口
  5. 测试ADC

模块驱动

目录

  1. 串口收发驱动(中断方式)
  2. LoRa收发驱动
  3. OLED显示驱动
  4. LED指示灯驱动
  5. ADC驱动
  6. 继电器驱动
  7. 矩阵键盘驱动
  8. 定时器驱动
  9. 温度传感器驱动
  10. 脉冲测量驱动
  11. EEPROM读写驱动
  12. 光敏与红外热释电驱动
  13. 按键(消抖)驱动

串口收发驱动

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 执行按键功能

      }
}

常用程序

目录

  1. 字符串/字符查找
  2. 串口打印封装
  3. 内存映射/拷贝
  4. 数据类型转换

字符串/字符查找

  • 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()函数的主要用途有三个:
  1. 将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能,
  2. 将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间,
  3. 为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。
#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
posted @ 2024-05-29 00:58  qsBye  阅读(9)  评论(0编辑  收藏  举报