STM32F103核心板板一块;
microUSB线一根(供电);
STLink板或USB串口板一块。
首先安装STM32CubeMX,并且下载相应的STM32的库,由于实验中采用的是STM32F103C8,因此这里下载STM32F1的库,如下图所示
然后新建一个工程,选择正确的板子型号(STM32F103C8Tx)
然后定义引脚,这里定义PA.09为USART1_TX,PA.10为USART1_RX
并且设定模式为异步,Hardware Flow Control为Disable
然后点击Project -> Generate Code生成代码,选择Toolchain为MDK-ARM V5。
再安装Keil软件,用来生成hex文件并且用其通过ST-LINK来下载到板子上运行。初次安装的时候需要下载相应的STM32设备包。
打开main.c中可以看到串口的初始化函数,按照要求设定串口的波特率为9600,数据的宽度为8,停止位为一位,没有检验位,然后用HAL_UART_Init函数初始化。
1 /* USART1 init function */ 2 void MX_USART1_UART_Init(void) 3 { 4 huart1.Instance = USART1; 5 huart1.Init.BaudRate = 9600; 6 huart1.Init.WordLength = UART_WORDLENGTH_8B; 7 huart1.Init.StopBits = UART_STOPBITS_1; 8 huart1.Init.Parity = UART_PARITY_NONE; 9 huart1.Init.Mode = UART_MODE_TX_RX; 10 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; 11 huart1.Init.OverSampling = UART_OVERSAMPLING_16; 12 HAL_UART_Init(&huart1); 13 }
然后这样子即可以采用HAL_UART_Transmit和HAL_UART_Receive两个函数进行串口的收发了。但是为了简单起见,这里重写了printf函数,以便可以用printf进行写入串口。重写int __io_putchar(int ch)和int fputc(int ch, FILE *f)两个函数
1 #ifdef __GNUC__ 2 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) 3 #else 4 #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) 5 #endif /* __GNUC__ */ 6 PUTCHAR_PROTOTYPE 7 { 8 9 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); 10 return ch; 11 }
然后即可以采用 printf 函数进行串口发送数据了。
然后我们在 main 中加入一行 printf(“Hello”);先串口写入 Hello 的函数。
然后开始配置 Keil,打开设置后首先选定设备为 STM32F103C8,然后在Output中勾选Create HEX File选项。然后在解散ST-LINk之后可以在Debug选项中可以看到ST-LINK的调试器,并且打开设备可以看到相关的设备名字说明ST-LINK连接成功。在连接ST-LINK之前需要安装ST-LINK的驱动,然后在设备管理器中就可以看到已经成功挂载的设备。
在以上设置完毕以后,编译源代码,然后选择Flash-> download就可以下载了。
后采用串口软件Putty读取串口上的数据,设置串口的属性如下
然后打开串口,并且按下STM32上面的reset键就可以在串口上看到Hello字样
在STM32CubeMX中加入两个GPIO输入PA11和PA12,设定其为GPIO_Input
然后在Keil中修改GPIO的初始化函数如下,设定PA11的方式为上拉输入,PA12为下降沿中断触发,初始化两个GPIO。
1 void MX_GPIO_Init(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStruct; 4 5 /* GPIO Ports Clock Enable */ 6 __HAL_RCC_GPIOA_CLK_ENABLE(); 7 8 /*Configure GPIO pins : PA11 PA12 */ 9 GPIO_InitStruct.Pin = GPIO_PIN_11; 10 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; 11 GPIO_InitStruct.Pull = GPIO_PULLUP; 12 GPIO_InitStruct.Speed = GPIO_SPEED_LOW; 13 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 14 GPIO_InitStruct.Pin = GPIO_PIN_12; 15 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; 16 GPIO_InitStruct.Pull = GPIO_PULLUP; 17 GPIO_InitStruct.Speed = GPIO_SPEED_LOW; 18 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 19 20 }
然后在main函数中加入GPIO的初始化函数,并且加入对于PA11的按下的检测函数,注意需要加上防抖动处理,否则会按下输出很多的Pressed
1 while (1) 2 { 3 /* USER CODE END WHILE */ 4 5 /* USER CODE BEGIN 3 */ 6 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) 7 { 8 HAL_Delay(100); //anti-jitter 9 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) 10 { 11 printf("Pressed\r\n"); 12 } 13 } 14 }
然后重新build工程,然后下载到板子上通过串口查看结果
在上面PA11的基础上进行修改,因此这里不需要添加引脚,不用STM32CubeMX。
首先配置PA12为下降边沿触发,在GPIO的初始化函数中如下设置
1 GPIO_InitStruct.Pin = GPIO_PIN_12; 2 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; 3 GPIO_InitStruct.Pull = GPIO_PULLUP; 4 GPIO_InitStruct.Speed = GPIO_SPEED_LOW; 5 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
然后设置中断的优先级,enable中断向量 表处理,在main函数中添加以下代码
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
当出现中断的时候,由于设定的引脚为PA12,因此当出现中断的时候,STM32会调用EXTI15_10_IRQHandler这个中断服务程序进行处理,我们在stm32f1xx_it.c中实现它,并在里面调用HAL_GPIO_EXTI_IRQHandler函数。由于上述函数会判断中断标志位并且调用HAL_GPIO_EXTI_Callback函数,因此我们将中断处理程序放在了HAL_GPIO_EXTI_Callback函数中进行实现。
1 void EXTI15_10_IRQHandler(void) 2 { 3 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12); 4 } 5 6 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 7 { 8 flag = 1; 9 counter = counter + 1; 10 }
对于全局变量的定义,我们在main.c中定影了两个全局变量flag和counter,然后在stm32f1xx_it.c中用extern关键词声明这两个变量以此达到两个c文件共享全局变量的效果。
然后在main的主循环中判断标志flag,如果其为1,则输出counter值,并且消除标志位。这里为了输出整形变量的值,我写了一个从unsigned int到字符串的函数,以便采用printf进行输出。
1 while (1) 2 { 3 /* USER CODE END WHILE */ 4 /* USER CODE BEGIN 3 */ 5 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) 6 { 7 HAL_Delay(100); //anti-jitter 8 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) 9 { 10 printf("Pressed\r\n"); 11 } 12 } 13 if(flag) 14 { 15 char s[33]; 16 toString(counter, s); 17 printf("%s\r\n", s); 18 flag = 0; 19 } 20 21 } 22 23 /** 24 *transform a integer into a string 25 *@num: The input number 26 *@s: The string after transforming 27 *@return void 28 */ 29 void toString(int num, char s[]) 30 { 31 int len = 0, tmp = num; 32 if(tmp==0) 33 len=1; 34 while(tmp != 0) 35 { 36 len++; 37 tmp /= 10; 38 } 39 s[len--] = ‘\0‘; 40 while(num != 0) 41 { 42 s[len--] = (num%10) + ‘0‘; 43 num /= 10; 44 } 45 }
然后重新编译代码,下板执行。通过下图可以看到,每次按下按钮会输出一个递增的数字,说明程序运行正确。
首先采用STM32CubeMX启用TIM3,并且采用内部时钟
然后生成代码,用Keil打开工程。
采用内部时钟,其频率为8MHz,配置时钟向上计数,计数到199,Prescaler的分频范围为0-65536,因此在这里设置为8000,,8MHz/8000 = 1000Hz = 1ms。
修改MX_TIM3_Init函数体如下,分别设置时钟为TIM3,Prescaler为8000,计数模式为向上计数,周期为199,时钟为内部时钟以及复位模式。然后设置中断的优先级,enable中断向量表处理。最后初始化定时器。
1 /* TIM3 init function */ 2 void MX_TIM3_Init(void) 3 { 4 TIM_ClockConfigTypeDef sClockSourceConfig; 5 TIM_MasterConfigTypeDef sMasterConfig; 6 7 TIM_Handle.Instance = TIM3; 8 TIM_Handle.Init.Prescaler = 8000; 9 TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; 10 TIM_Handle.Init.Period = 199; 11 12 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 13 // HAL_TIM_ConfigClockSource(&TIM_Handle, &sClockSourceConfig); 14 15 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 16 HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); 17 HAL_NVIC_EnableIRQ(TIM3_IRQn); 18 19 HAL_TIM_Base_Init(&TIM_Handle); 20 }
然后在stm32f1xx_hal_msp.c中的HAL_TIM_Base_MspInit中enable定时器时钟,在HAL_TIM_Base_MspDeInit中disable定时器时钟(如果采用STM32CubeMX生成,其会自动生成该代码,否则就需要自己添加)。
由于定时器中断调用TIM3_IRQHandler函数,因此我们在stm32f1xx_it.c中编写中断服务程序TIM3_IRQHandler函数。由于在其中要用HAL_TIM_IRQHandler
(&TIM_Handle),因此在stm32f1xx_it.c采用extern申明TIM_Handle。由于该服务程序会调用HAL_TIM_PeriodElapsedCallback回调函数,因此在其中加入中断处理的程序。在这里我加的是一个将标志位置位,然后将一个全局变量加上10的一个操作。
1 void TIM3_IRQHandler(void) 2 { 3 HAL_TIM_IRQHandler(&TIM_Handle); 4 } 5 6 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 7 { 8 timeFlag = 1; 9 counter += 10; 10 }
然后在main中HAL_TIM_Base_Start_IT(&TIM_Handle)启动定时器,在主循环中输出counter的值来检验定时中断。
1 while (1) 2 { 3 /* USER CODE END WHILE */ 4 5 /* USER CODE BEGIN 3 */ 6 //time interrupt 7 if(timeFlag) 8 { 9 char s[33]; 10 toString(counter, s); 11 printf("%s\r\n", s); 12 timeFlag = 0; 13 } 14 /* USER CODE END 3 */ 15 }
然后重新编译代码,将其载入板子运行,通过串口观看结果。通过下图可以看到,串口上不断输出了以10递增的一些列数字,说明定时中断正常工作。
原文:http://www.cnblogs.com/jackwang822/p/5400605.html