一、 实验目的和要求
1. 理解MCU上电启动过程;
2. 掌握使用Cube库来编写STM32裸机程序的方法;
3. 掌握使用Cube库来编写GPTO和UART程序的方法;
4. 掌握使用Cube库来编写中断响应程序的方法;
5. 理解前后台程序模式
6. 掌握在STM32F103上编写裸机程序并下载运行的方法。
二、 实验器材
1. STM32F103核心板一块;
2. MicroUSB线一根;
3. STLink板或USB串口板一块;
4. 交叉编译软件
三、 实验内容和原理
1.编写Cube程序,配置UART0为9600,8n1,上电后向串口输出“Hello”,在PC上通过串口软件观察结果
2.通过面包板在PA11和PA12各连接一个按钮开关到地
3.编写Cube程序,配置PA11和PA12为内部上拉到输入模式,在main()函数循环检测PA11按钮按下,并在按钮按下时在串口输出Pressed。
4.编写Cube程序,配置PA12下降沿触发中断,程序中设置两个全局变量,一个为计数器,一个为标识。当中断触发时,计数器加1,并设置标识。在主循环中判断标识,如果标识置位则清除标识并通过串口输出计数值;
5.编写Cube程序,开启定时器为200ms中断一次,中断触发时设置标识,主循环根据这个标识来做串口输出(取消4的串口输出);
6.编写完整的码表程序,PA12的按钮标识车轮转了一圈,通过计数器可以得到里程,通过定时器中断得到的时间可以计算出速度;PA的按钮切换模式,模式一在串口输出里程,模式二在串口输出速度。
四、 实验过程和数据记录
1. 下列图片为实物连接图
其中串口使用PA9,PA10;GPIO使用PA11,PA12,分别连接按钮。黑线接地。
2. 在Cube软件中配置UART0的波特率为9600, 8n1,然后向串口输出Hello,通过Mac上的串口软件观察结果。
a. 下图为配置图片,将波特率设置为9600,8n1.
b. 配置完成后,我们就可以用HAL_UART_Transmit和HAL_UART_Receive两个函数来进行串口的收发数据。使用GNUC需要重写__io_putchar和fputc函数,我们通过宏定义来完成。
c. 测试串口输出,在while循环前添加printf函数来输出Hello
d. 下面是实验结果展示图
3. 编写Cube程序,配置PA11和PA12为内部上拉到输入模式,在main()函数循环检测PA11按钮按下,并在按钮按下时在串口输出Pressed
a. 首先配置PA11和PA12为内部上拉到输入模式,如下图所示
b. 在while循环中写出如果按下按钮,则在串口输出Pressed字样,循环代码如下图所示
c. 下面是输出图示
4. 编写Cube程序,配置PA12下降沿触发中断,程序中设置两个全局变量,一个为计数器,一个为标识。当中断触发时,计数器加1,并设置标识。在主循环中判断标识,如果标识置位则清除标识并通过串口输出计数值
a. 配置PA12下降沿触发中断,配置过程如下
b. 设置两个全局变量stopwatch_counter和stopwatch_flag,并且实现HAL_GPIO_EXTI_Callback(unit16_tGPIO_Pin)函数,函数实现如下
c. 在while循环中,通过判断全局变量stopwatch_flag的值,来判断中断是否发生,代码实现如下
d. 成功编译之后下载到板子上,运行结果如下图所示
5. 编写Cube程序,开启定时器为200ms中断一次,中断触发时设置标识,主循环根据这个标识来做串口输出(取消4的串口输出)
a. 配置时钟信息如下
b. 实现HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)函数,用来设置标识符
c. 在main函数初始化定时器,并且根据stopwatch_flag来判断中断是够发生。实现代码如下
d. 在串口软件监测到如下结果
6. 编写完整的码表程序,PA12的按钮标识车轮转了一圈,通过计数器可以得到里程,通过定时器中断得到的时间可以计算出速度;PA的按钮切换模式,模式一在串口输出里程,模式二在串口输出速度。
a. 在计算速度和里程的过程中,里程默认中断一次为1m,速度计算公式为stopwatch_mile*18/stopwatch_time,stopewatch_time为添加的全局变量,表示定时器的中断次数。
b. 完整代码如下
/** ****************************************************************************** * File Name : main.c * Description : Main program body ****************************************************************************** * * COPYRIGHT(c) 2016 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f1xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/
int stopwatch_counter; int stopwatch_flag; int stopwatch_time; int stopwatch_mode;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); static void MX_TIM2_Init(void);
/* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to ‘Yes‘) calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
int main(void) {
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init();
/* Configure the system clock */ SystemClock_Config();
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_TIM2_Init();
/* USER CODE BEGIN 2 */ GPIO_PinState key; HAL_TIM_Base_Start_IT(&htim2); printf("Hello\n\r");
double mile = 0; double speed = 0;
/* USER CODE END 2 */
/* Infinite loop */ /* USER CODE BEGIN WHILE */
while (1) { /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11); if (key == GPIO_PIN_RESET) { stopwatch_mode = !stopwatch_mode; } if (stopwatch_flag == 1) { stopwatch_flag = 0;
mile = stopwatch_counter * 1; if (stopwatch_mode == 0) { printf("Current Mile: %f\n\r", mile); } else { speed = stopwatch_counter / stopwatch_time; printf("Current Speed: %1f\n\r", speed); } } HAL_Delay(100);
} /* USER CODE END 3 */
}
/** System Clock Configuration */ void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); }
/* TIM2 init function */ void MX_TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig; TIM_MasterConfigTypeDef sMasterConfig;
htim2.Instance = TIM2; htim2.Init.Prescaler = 8000; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 199; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}
/* USART1 init function */ void MX_USART1_UART_Init(void) {
huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1);
}
/** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA11 */ GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PA12 */ GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/* USER CODE BEGIN 4 */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch; }
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_12) { stopwatch_counter += 1; // stopwatch_flag = 1; } }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { stopwatch_flag = 1; stopwatch_time += 1; }
}
/* USER CODE END 4 */
#ifdef USE_FULL_ASSERT
/** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */
}
#endif
/** * @} */
/** * @} */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
c. 下面是实验结果图展示
7. 扩展内容
a. 扩展内容由于工程具有完整性,故统一完成如下
b. Main函数中代码较为简单,为休眠操作,由于SysTick中断也会终止休眠,故应该关掉中断。
int main(void) { HAL_Init();
/* Configure the system clock */ SystemClock_Config();
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_TIM2_Init();
/* USER CODE BEGIN 2 */ GPIO_PinState key; HAL_TIM_Base_Start_IT(&htim2); printf("Hello\n\r");
/* USER CODE END 2 */ while (1) { /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_SuspendTick(); __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); HAL_ResumeTick(); } /* USER CODE END 3 */
} |
c. 下面是中断处理函数的修改
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
double mile = 0; double speed = 0;
if (htim->Instance == TIM2) { // stopwatch_flag = 1; stopwatch_time += 1;
mile = stopwatch_counter*1; if (stopwatch_mode == 0) { printf("Current Mile: %f\n\r", mile); } else { speed = (double)stopwatch_counter / stopwatch_time; printf("Current Speed: %1f\n\r", speed); } }
} |
d. 下面是实验结果图
可以看出和之前实验的输出结果相类似,实验成功。