摘要
整理藍橋杯物聯網必背筆記.
關鍵資訊
- 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 |