电量仪DIY手记——基本输入与输出系统(附Keil使用窍门)
在大多数的项目里,我们都需要有用户交互,或通过键盘,或通过网口,至少也会有LED灯的指示。今天我们就利用STM32L053套件的绿色指示灯、蓝色按键再加上串口显示来实现一个基本的用户交互。
考虑目前为实验,所以我们使用ST官方提供的代码生成软件STcubeMx来自动生成项目文件。我们需要配置下列几项:
1、为了方便配置我们首先选择Nucleo-STM32L053开发板,这样绿色的指示灯引脚,蓝色按键以及串口都为我们选定好了。
2、修改蓝色按键的引脚配置方式,原方案为边沿触发中断的方式,我们需要修改为普通输入的方式,因为我们要使用按键扫描的方式来获取按键状态。这里注意一下,按键在开发板上为硬件的上拉电阻,即按键引脚PC13默认值为高电平,在有按键按下时为低电平。
3、串口的方式我们使用DMA发送,接收使用中断的方式来实现。这里我们先行实现DMA方式。
4、我们再配置TIM21来实现按键扫描的中断处理,这里仅使用update中断,即溢出中断。我们设置为10ms触发一次中断。
配置完成我们就可以生成项目了,还是挺方便的。
我们在生成的项目源代码里仍然需要编写自己的代码,如启动中断以及串口DMA的地址配置等等。有兴趣大家可以参照一下源代码:
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
#include "key.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
extern KeyCodeClass gKeyCode;
const char WelcomeStr[] = "hello EEPW!\r\n";
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static void LL_Init(void);
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_LPTIM1_Init(void);
static void MX_TIM21_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
const uint16_t SLOT_25MS = 409;
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_LPTIM1_Init();
MX_TIM21_Init();
/* USER CODE BEGIN 2 */
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t)WelcomeStr);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, 0x40004428);
LL_USART_EnableDMAReq_TX(USART2);
/* config LPTIM1 */
LL_LPTIM_EnableIT_CMPM(LPTIM1);
LL_LPTIM_Enable(LPTIM1);
LL_LPTIM_SetAutoReload(LPTIM1, 0xFFFF);
LL_LPTIM_SetCompare(LPTIM1, 20 * SLOT_25MS);
LL_LPTIM_StartCounter(LPTIM1, LL_LPTIM_OPERATING_MODE_CONTINUOUS);
/* LPTIM1 interrupt Init */
NVIC_SetPriority(TIM21_IRQn, 0);
NVIC_EnableIRQ(TIM21_IRQn);
LL_TIM_EnableIT_UPDATE(TIM21);
LL_TIM_EnableCounter(TIM21);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(gKeyCode.Click == 0x01)
{
gKeyCode.Click = 0;
LL_mDelay(500);
LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 13);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
}
}
/* USER CODE END 3 */
}
static void LL_Init(void)
{
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/* System interrupt init*/
/* SVC_IRQn interrupt configuration */
NVIC_SetPriority(SVC_IRQn, 0);
/* PendSV_IRQn interrupt configuration */
NVIC_SetPriority(PendSV_IRQn, 0);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, 0);
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
{
Error_Handler();
}
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_RCC_MSI_Enable();
/* Wait till MSI is ready */
while(LL_RCC_MSI_IsReady() != 1)
{
}
LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);
LL_RCC_MSI_SetCalibTrimming(0);
LL_PWR_EnableBkUpAccess();
LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_LOW);
LL_RCC_LSE_Enable();
/* Wait till LSE is ready */
while(LL_RCC_LSE_IsReady() != 1)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_MSI);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_MSI)
{
}
LL_Init1msTick(4194000);
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(4194000);
LL_RCC_SetUSARTClockSource(LL_RCC_USART2_CLKSOURCE_PCLK1);
LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE);
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, 0);
}
/* LPTIM1 init function */
static void MX_LPTIM1_Init(void)
{
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1);
/* LPTIM1 interrupt Init */
NVIC_SetPriority(LPTIM1_IRQn, 0);
NVIC_EnableIRQ(LPTIM1_IRQn);
LL_LPTIM_SetClockSource(LPTIM1, LL_LPTIM_CLK_SOURCE_INTERNAL);
LL_LPTIM_SetPrescaler(LPTIM1, LL_LPTIM_PRESCALER_DIV2);
LL_LPTIM_SetPolarity(LPTIM1, LL_LPTIM_OUTPUT_POLARITY_REGULAR);
LL_LPTIM_SetUpdateMode(LPTIM1, LL_LPTIM_UPDATE_MODE_IMMEDIATE);
LL_LPTIM_SetCounterMode(LPTIM1, LL_LPTIM_COUNTER_MODE_INTERNAL);
LL_LPTIM_TrigSw(LPTIM1);
}
/* TIM21 init function */
static void MX_TIM21_Init(void)
{
LL_TIM_InitTypeDef TIM_InitStruct;
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM21);
TIM_InitStruct.Prescaler = 2096;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 9;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV2;
LL_TIM_Init(TIM21, &TIM_InitStruct);
LL_TIM_SetClockSource(TIM21, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_SetTriggerOutput(TIM21, LL_TIM_TRGO_UPDATE);
LL_TIM_DisableMasterSlaveMode(TIM21);
}
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
LL_USART_InitTypeDef USART_InitStruct;
LL_GPIO_InitTypeDef GPIO_InitStruct;
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = USART_TX_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(USART_TX_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USART_RX_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
LL_GPIO_Init(USART_RX_GPIO_Port, &GPIO_InitStruct);
/* USART2 DMA Init */
/* USART2_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_4);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
/* USART2 interrupt Init */
NVIC_SetPriority(USART2_IRQn, 0);
NVIC_EnableIRQ(USART2_IRQn);
USART_InitStruct.BaudRate = 9600;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART2, &USART_InitStruct);
LL_USART_DisableOverrunDetect(USART2);
LL_USART_ConfigAsyncMode(USART2);
LL_USART_Enable(USART2);
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* Init with LL driver */
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* DMA interrupt init */
/* DMA1_Channel4_5_6_7_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel4_5_6_7_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
LL_GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOH);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
/**/
LL_GPIO_ResetOutputPin(LD2_GPIO_Port, LD2_Pin);
/**/
GPIO_InitStruct.Pin = LL_GPIO_PIN_13;
GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/**/
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/窍门:我们使用Keil打开项目后,首先编译一下(快捷键F7),这样的好处是Keil就能够识别我们关键字与函数了,可以方便关键词提示与函数跳转(光标在关键词或者函数上时按F12就快速跳转了)。

我要赚赏金
