stm32筆記[15]-藍橋物聯網筆記整理

qsBye發表於2024-05-29

摘要

整理藍橋杯物聯網必背筆記.

關鍵資訊

  • 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

相關文章