首页 > 其他 > 详细

STM32上电启动以及Cube库的程序编写

时间:2016-04-17 12:59:17      阅读:661      评论:0      收藏:0      [点我收藏+]

器材

硬件

  • STM32F103核心板板一块;

  • microUSB线一根(供电);

  • STLink板或USB串口板一块。

软件

  • 交叉编译软件。
  • STM32CubeMX, Keil
  • 串口软件Putty

连接示意图

 技术分享

技术分享

实验步骤

串口输出Hello

STM32CubeMX

首先安装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

再安装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 的函数。

ST-LINK 下载

然后开始配置 Keil,打开设置后首先选定设备为 STM32F103C8,然后在Output中勾选Create HEX File选项。然后在解散ST-LINk之后可以在Debug选项中可以看到ST-LINK的调试器,并且打开设备可以看到相关的设备名字说明ST-LINK连接成功。在连接ST-LINK之前需要安装ST-LINK的驱动,然后在设备管理器中就可以看到已经成功挂载的设备。

在以上设置完毕以后,编译源代码,然后选择Flash-> download就可以下载了。

Putty

后采用串口软件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工程,然后下载到板子上通过串口查看结果

 

PA12中断响应

在上面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递增的一些列数字,说明定时中断正常工作。

 

STM32上电启动以及Cube库的程序编写

原文:http://www.cnblogs.com/jackwang822/p/5400605.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!