Lab3 自行车码表

实验连接示意图

整体图

STM32和USB连接图

STM32和STLink连接图

面包板

实验步骤

  1. 连接STM32和其他设备,并下载安装mdk等所需软件。
  2. 编写Cube程序,配置UART0为9600,8n1,上电后向串口输出“Hello”,在PC上通过串口软件观察结果。结果如下:
  3. 编写Cube程序,配置PA11和PA12为内部上拉到输入模式,在main()函数循环检测PA11按钮按下,并在按钮按下时在串口输出“Pressed”。结果如下:
  4. 编写Cube程序,配置PA12下降沿触发中断,程序中设置两个全局变量,一个为计数器,一个为标识。当中断触发时,计数器加1,并设置标识。在主循环中判断标识,如果标识置位则清除标识并通过串口输出计数值。结果如下,当PA12按下时,count加1并显示。
  5. 编写Cube程序,开启定时器为200ms中断一次,中断触发时设置标识,主循环根据这个标识在做串口输出(取消4的串口输出)。结果如下,定时输出count。
  6. 编写完成的码表程序,PA12的按钮标识车轮转了一圈,通过计数器可以得到里程,通过定时器中断得到的时间可以计算出速度;PA11的按钮切换模式,模式一在串口输出里程,模式二在串口输出速度。具体显示结果见“四、结果与分析”

    源代码

    main.c

1
2
#include <stdio.h>
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_uart.h"
#include "stm32f1xx_hal_tim.h"
void SystemClock_Config(void); static void Error_Handler(void); static void MX_GPIO_Init(void); static void MX_TIM3_Init(void); UART_HandleTypeDef UartHandler; TIM_HandleTypeDef TIM_Handler; int pa12_interrupt_flag; int timer_flag; int counter=0; int timer_counter=0; int mode=0; int state1; int main(void) { HAL_Init(); // 设置时钟 SystemClock_Config(); // 初始化 MX_TIM3_Init(); MX_GPIO_Init(); HAL_TIM_Base_Start_IT(&TIM_Handler); // 配置UART1 UartHandler.Instance = USART1; UartHandler.Init.BaudRate = 9600; UartHandler.Init.WordLength = UART_WORDLENGTH_8B; UartHandler.Init.StopBits = UART_STOPBITS_1; UartHandler.Init.Parity = UART_PARITY_NONE; UartHandler.Init.HwFlowCtl = UART_HWCONTROL_NONE; UartHandler.Init.Mode = UART_MODE_TX_RX; // 初始化UART HAL_UART_Init(&UartHandler); HAL_Delay(100); printf("Hello\r\n"); // 开机输出hello int flag = 0; HAL_SuspendTick(); while (1) { // 轮询PA11 state1 = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11); if(state1==0) // 按下PA11切换模式 mode = ~mode; } } int __io_putchar(uint8_t ch){ // 输出字符 HAL_UART_Transmit(&UartHandler, &ch, 1, 100); return 1; } int fputc(int ch, FILE *f){ uint8_t chr =ch; HAL_UART_Transmit(&UartHandler, &chr, 1, 100); return 1; } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ // 回调函数 if(htim->Instance == TIM3){ timer_flag = 1; timer_counter++; } if (mode) // 模式一 printf("speed=%lf\r\n", counter*1.0/timer_counter); else // 模式二 printf("distance=%d\r\n", counter); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ switch (GPIO_Pin){ case GPIO_PIN_11: printf("Pressed\r\n"); mode=!mode; break; case GPIO_PIN_12: counter++; break; } } /** 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_SYSCLK; 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); } // 时钟初始化 void MX_TIM3_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig; TIM_MasterConfigTypeDef sMasterConfig; TIM_Handler.Instance = TIM3; TIM_Handler.Init.Prescaler = 8000; TIM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; TIM_Handler.Init.Period = 199; TIM_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&TIM_Handler); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&TIM_Handler, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&TIM_Handler, &sMasterConfig); } // GPIO初始化 void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } #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 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) */ } #endif

stm32f1xx_hal_msp.c

1
void HAL_MspInit(void)
{

  __HAL_RCC_AFIO_CLK_ENABLE();

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* System interrupt init*/
/* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

    /**DISABLE: JTAG-DP Disabled and SW-DP Disabled 
    */
  

}
// 初始化
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_USART1_CLK_ENABLE();
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.Pin = GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	GPIO_InitStruct.Pin = GPIO_PIN_10;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 善后
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
	__HAL_RCC_USART1_FORCE_RESET();
	__HAL_RCC_USART1_RELEASE_RESET();
	HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9);
	HAL_GPIO_DeInit(GPIOA, GPIO_PIN_10);
}
// 初始化
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM3)
  {
    __TIM3_CLK_ENABLE();
    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  }
}
// 善后
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base) 
{

  if(htim_base->Instance==TIM3)
  {
    __TIM3_CLK_DISABLE();
    HAL_NVIC_DisableIRQ(TIM3_IRQn);
  }
}

结果与分析


如上图,是自行车码表的运行结果。当按下STM32上的reset时,码表被重启,并向串口发送“Hello”。启动后默认在模式一下运行,根据定时器输出里程,按当下P11时切换模式,在模式二下运行并根据定时器输出速度,符合实验预期。但由于未对按键进行去抖,可能会出现像第一次那样按下一次PA11却连续出现两次“Pressed”的情况。