基于stm32f103c8t6、HAL库定时器控制灯亮灭&&PWM实现呼吸灯

目录

 

一、定时器简介

1.  功能简介

2. 计数器模式

3. 时基单元

4. 定时器时钟源

二、PWM简介

三、任务要求

四、STM32CubeMX配置

   1.  选择stm32f03c8t6芯片

   2.  配置RCC

   3. 配置sys

   4. 配置UART1

   5. 配置DMA

   6. 配置TIM2&&TIM3

   7.  配置时钟

   8. 配置中断

   9. 工程输出配置

五、程序编写

1. 定时器函数介绍

2. TIM2程序编写

3. TIM3程序编写

六、实物效果和仿真效果

  1. 实物效果 

 2. 仿真效果

七、总结与参考


 

一、定时器简介

1.  功能简介

          STM32 的定时器功能十分强 大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和 TIME7 等基本定时器。

          三种定时器功能如下:

835d32eaec0f4a96b5f685a129f334a3.png

         STM32 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT) 构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波 形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形 周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相 共享的任何资源。 STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:

通用定时器功能
1. 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
2. 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~ 65535 之间的任意数值。
3. 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4. 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外 一个定时器)的同步电路。
5. 如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
a7aaa0a49c8a4a95bf777f7fb90aa9db.png
 

2. 计数器模式

  • 向上计数模式
在向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始
计数并且产生一个计数器溢出事件。
  • 向下计数模式
在向下模式中,计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动
装入的值重新开始并且产生一个计数器向下溢出事件。
  • 中央对齐计数模式

在中央对齐模式,计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。

3. 时基单元

      可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可
以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。 计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。
时基单元包含:
时基单元
计数器寄存器(TIMx_CNT)向上计数、向下计数或者中心对齐计数
预分频器寄存器 (TIMx_PSC)可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值;
自动装载寄存器 (TIMx_ARR)

如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器;

如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。

 

定时器频率=时钟频率/(PSC+1)(ARR+1)

9957f3afb45347e5b6c2b5d130ec2823.png

 

4. 定时器时钟源

定时器的时钟来源有 4 个:
1)内部时钟(CK_INT)
2)外部时钟模式 1:外部输入脚(TIx)
3)外部时钟模式 2:外部触发输入(ETR)
4)内部触发输入(ITRx):使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟)。
这些时钟,具体选择哪个可以通过 TIMx_SMCR 寄存器的相关位来设置。这里的 CK_INT
时钟是从 APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1,否则通用定时器 TIMx 的时钟
是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于 APB1
的时钟。

二、PWM简介

     脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用 微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制,PWM 原理如图 :

888363b4307d49e1b28b6294a27cb083.png

 

       我们假定定时器工作在向上计数 PWM 模式,且当 CNT<CCRx 时,输出 0,当 CNT>=CCRx 时输出 1。那么就可以得到如上的 PWM 示意图:当 CNT 值小于 CCRx 的时候,IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候, IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。 改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的 频率,这就是 PWM 输出的原理。 STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定 时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!这里我们仅使用 TIM3 的 CH2 产生一路 PWM 输出。如果要产生多路输出,大家可以根据我们的代码稍作修改即可。
PWM占空比=CRR/ARR

三、任务要求

      一、使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。

      二、接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。

      三、再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。

四、STM32CubeMX配置

        在次实验中,使用两个通用定时器,TIM2用来定时器中断,每1s就中断一次,控制PA1电平反转(LED阳极接PA1),TIM2用来PWM输出,控制PA2(LED阳极接PA2)实现呼吸灯的效果。

 

 1.  选择stm32f03c8t6芯片

0f78bb15158149009d0471dab7a785d9.png

         2.  配置RCC

51253c5c996f475da0d72c27108e2a88.png

          3. 配置sys

34d0c22ba06a413b87bdb2e848eba8b9.png

          4. 配置UART1

6113098f54424707b4ebb3050f0f4ebd.png

1892bde9772048ceafed645945df758e.png

   5. 配置DMA 

       315478ebe6b343f79d94038863a8d826.png   

af52fcf5b6f349d9849476884ec09703.png 215243c5ba6c4602802f77e2cec47e7d.png

   6. 配置TIM2&&TIM3

e444bd925dc34913b798eb430bdf470d.png

c920803bebe441b8bd24e86e5dd91a6f.png

 

   7.  配置时钟

86536071cf9649d0a3de44597c0bfa2b.png

8. 配置中断

1f80810c703644b2b1290fd4fc3eebce.png

9. 工程输出配置

0dc97deb50c04e5691904e68ede8c8f6.png

9ed33fce40774f6fbcd33445c9b4a8d2.png

 

五、程序编写

       通过上诉配置,已经在Keil中完成了我们需要的配置,下面需要完成程序。介绍一些常用的定时器函数

1. 定时器函数介绍

1 TIM  时钟使能。
     HAL 中定时器使能是通过宏定义标识符来实现对相关寄存器操作的,方法如下:
__HAL_RCC_TIM3_CLK_ENABLE(); //使能 TIM3 时钟
2 )初始化定时器参数 , 设置自动重装值,分频系数,计数方式等。
     在 HAL库中,定时器的初始化参数是通过定时器初始化函数 HAL_TIM_Base_Init 实现的:
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim);
该函数只有一个入口参数,就是 TIM_HandleTypeDef 类型结构体指针,结构体类型为下面
我们看看这个结构体的定义:
typedef struct
{
TIM_TypeDef *Instance;
TIM_Base_InitTypeDef Init;
HAL_TIM_ActiveChannel
Channel;
DMA_HandleTypeDef
*hdma[7];
HAL_LockTypeDef Lock;
__IO HAL_TIM_StateTypeDef State;
}TIM_HandleTypeDef;
     第一个参数 Instance 是寄存器基地址。和串口,看门狗等外设一样,一般外设的初始化结
构体定义的第一个成员变量都是寄存器基地址。这在HAL中都定义好了,比如要初始化串口1,
那么 Instance 的值设置为 TIM1 即可。
     第二个参数 Init 为真正的初始化结构体 TIM_Base_InitTypeDef 类型。该结构体定义如下:
typedef struct
{
uint32_t Prescaler;
//预分频系数
uint32_t CounterMode; //计数方式
uint32_t Period;
//自动装载值 ARR
uint32_t ClockDivision; //时钟分频因子
uint32_t RepetitionCounter;
} TIM_Base_InitTypeDef;
      该初始化结构体中,参数 Prescaler 是用来设置分频系数的,刚才上面有讲解。参数
CounterMode 是用来设置计数方式,可以设置为向上计数,向下计数方式还有中央对齐计数方
式 , 比 较 常 用 的 是 向 上 计 数 模 式 TIM_CounterMode_Up 和 向 下 计 数 模 式
TIM_CounterMode_Down。参数 Period 是设置自动重载计数周期值。参数 ClockDivision 是用来
设置时钟分频因子,也就是定时器时钟频率 CK_INT 与数字滤波器所使用的采样时钟之间的分
频比。参数 RepetitionCounter 用来设置重复计数器寄存器的值,用在高级定时器中。
第三个参数 Channel 用来设置活跃通道。前面我们讲解过,每个定时器最多有四个通道可
以用来做输出比较,输入捕获等功能之用。这里的 Channel 就是用来设置活跃通道的,取值范
围为:HAL_TIM_ACTIVE_CHANNEL_1~ HAL_TIM_ACTIVE_CHANNEL_4。
第四个 hdma 是定时器的 DMA 功能时用到,为了简单起见,我们暂时不讲解太复杂。
第五个参数 Lock 和 State,是状态过程标识符,是 HAL库用来记录和标志定时器处理过程。
定时器初始化范例如下:
TIM_HandleTypeDef TIM3_Handler;
//定时器句柄
TIM3_Handler.Instance=TIM3; //通用定时器 3
TIM3_Handler.Init.Prescaler= 7199;
//分频系数
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
//向上计数器
TIM3_Handler.Init.Period=4999;
//自动装载值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
HAL_TIM_Base_Init(&TIM3_Handler);
3 )使能定时器更新中断,使能定时器
HAL 库 中 , 使 能 定 时 器 更 新 中 断 和 使 能 定 时 器 两 个 操 作 可 以 在 函 数
HAL_TIM_Base_Start_IT()中一次完成的,该函数声明如下:
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
 该 函 数 非 常 好 理 解 , 只 有 一 个 入 口 参 数 。 调 用 该 定 时 器 之 后 , 会 首 先 调 用
__HAL_TIM_ENABLE_IT 宏定义使能更新中断,然后调用宏定义__HAL_TIM_ENABLE 使能
相应的定时器。这里我们分别列出单独使能/关闭定时器中断和使能/关闭定时器方法:
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);//使能句柄指定的定时器更新中断
__HAL_TIM_DISABLE_IT (htim, TIM_IT_UPDATE);//关闭句柄指定的定时器更新中断
__HAL_TIM_ENABLE(htim);//使能句柄 htim 指定的定时器
__HAL_TIM_DISABLE(htim);//关闭句柄 htim 指定的定时器
4 TIM3 中断优先级设置。
在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中
断优先级。之前多次讲解到中断优先级的设置,这里就不重复讲解。
和串口等其他外设一样,HAL 库为定时器初始化定义了回调函数 HAL_TIM_Base_MspInit。
一般情况下,与 MCU 有关的时钟使能,以及中断优先级配置我们都会放在该回调函数内部。
函数声明如下:
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim);
对于回调函数,这里我们就不做过多讲解,大家只需要重写这个函数即可。
5 )编写中断服务函数。
在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。通
常情况下,在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执
行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处
理完中断之后应该向 TIM3_SR 的最低位写 0,来清除该中断标志。
跟串口一样,对于定时器中断,HAL 库同样为我们封装了处理过程。这里我们以定时器 3
的更新中断为例来讲解。
首先,中断服务函数是不变的,定时器 3 的中断服务函数为:
TIM3_IRQHandler();
一般情况下我们是在中断服务函数内部编写中断控制逻辑。但是 HAL 库为我们定义了 新
的定时器中断共用处理函数 HAL_TIM_IRQHandler,在每个定时器的中断服务函数内部,我们
会调用该函数。该函数声明如下:
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);
而函数 HAL_TIM_IRQHandler 内部,会对相应的中断标志位进行详细判断,判断确定中断
来源后,会自动清掉该中断标志位,同时调用不同类型中断的回调函数。所以我们的中断控制
逻辑只用编写在中断回调函数中,并且中断回调函数中不需要清中断标志位。
比如定时器更新中断回调函数为:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
跟串口中断回调函数一样,我们只需要重写该函数即可。对于其他类型中断,HAL 库同样
提供了几个不同的回调函数,这里我们列出常用的几个回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//更新中断
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);//输出比较
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//输入捕获
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim);//触发中断

2. TIM2程序编写

      中断函数编写:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if(htim->Instance==TIM2)//判断是否为TIM2触发的中断
 {

  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);//反转PA1的电平
 }
}

   主函数添加中断使能:   

HAL_TIM_Base_Start_IT(&htim2);

3. TIM3程序编写

   修改占空比编写:

  while (1)
{
		while(duty<=10000)
		{
     duty++;
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		 Duty=(float)duty;
		 Duty/=100;
	 	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
     HAL_Delay(1);
		}
		while(duty>=0)
		{
			duty--;
		 __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		Duty=(float)duty;
	  Duty/=100;
	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
			 HAL_Delay(1);
		} 
}

PWM输出使能:

HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);

printf重定义函数:

int fputc(int c,FILE *f)
{
    uint8_t ch; 
    ch = c;
    HAL_UART_Transmit(&huart1,&ch,1,1000);
    return c;
}

主函数完整源码:

int main(void)
{

   int duty=0;
	 float  Duty;
	char str1[6]="Duty: ";
	char str2[]="%";
  HAL_Init();

  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);	//??TIM1?PWM Channel1 ??
	HAL_TIM_Base_Start_IT(&htim2);
  while (1)
{
		while(duty<=10000)
		{
     duty++;
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		 Duty=(float)duty;
		 Duty/=100;
	 	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
     HAL_Delay(1);
		}
		while(duty>=0)
		{
			duty--;
		 __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		Duty=(float)duty;
	  Duty/=100;
	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
			 HAL_Delay(1);
		} 
}

}

 

六、实物效果和仿真效果

  1. 实物效果 

                  6cd11c919d0a4d3bb3e085456dd428fc.gif

549d76d261f84ece898a457ceeff2139.gif

从图中看出,左边那个LED灯(PA1),1s闪烁一次,右边那个LED灯(PA6)闪烁的时间是从快到慢,再到快的,没有实现呼吸灯效果,这是由于我们配置的PWM频率为1hz,其中低电平部分时间延拓过长,人眼很容易识别出来,解决此方法的办法就是可以增大PWM的频率,如修改其周期为10ms,可以看出来有呼吸灯的效果:

修改PWM频率:

TIM3初始化代码(这里把PSC从7200-1修改为720-1,ARR从10000-1修改为1000-1)

static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 720-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 1000-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 50;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

循环内修改:

 while (1)
{
		while(duty<=700)//大于700的效果和700一样,设置为700效果更好
		{
     duty++;
		__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		 Duty=(float)duty;
		 Duty/=10;
	 	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
     HAL_Delay(1);
		}
		while(duty>=0)
		{
			duty--;
		 __HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,duty);
		Duty=(float)duty;
	  Duty/=10;
	 printf("%s",str1);
	 	 printf("%f",Duty);
	   printf("%s\n",str2);
			 HAL_Delay(1);
		} 
}

修改后效果:

50cb457321f8414b889a7b8a1c131a4f.gif

可以看出右边有呼吸灯效果

2. 仿真效果

环境配置:

13625f488bd743b4a4f5a4bc4fd738c9.png

ac0a2abb1c0f40fabd543f7b39a5c405.png

 

3c4ff3392bc94717b6aa033c6a4fa627.png

可以看出,二者周期都是1s,下面的波形占空比先从大到小,再从小到大,波形十分明显。

七、总结与参考

1. 通过次实验,理解和掌握了定时器的原理,以及如何通过HAL库使用定时器和通过定时器输出PWM。

2. 此实验中,设置的PSC=7200-1,ARR=10000-1,系统频率为72Mhz,那么可以得出PA1灯翻转周期和PWM的输出周期都为1s,从仿真图中,可以很清楚的看出都为1s。在之前的实验中,都是通过软件延时的方式进行延时,但是软件延时存在很不好的缺点,那就是不准确且浪费CPU资源,通过定时器的方式解决了这种缺点。

3. 在进行呼吸灯效果测试时,发现当PWM周期很大时,呼吸灯效果十分不明显,可以从PWM波原理上看,修改的只是高电平的占比,那么如果周期很大,即使占空比怎么修改,人眼中还是会看出来亮灭的过程,当PWM频率提高时,人眼就无法识别出低电平的间隙,从而看出来是从亮到灭的过程。

参考:

stm32F103定时器的pwm输出模式的常用运算_pwm周期计算公式_·H··的博客-CSDN博客

STM32-HAL-串口的printf重定向_hal printf 重定向-CSDN博客

【精选】STM32-定时器详解_stm32定时器-CSDN博客

 

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F103C8T6 HAL库是针对STM32F103C8T6开发板的硬件抽象层库。它包含了一系列的文件夹,如CORE、HALLIB、OBJ、PRO、SYSTEM和USER等。这个库可以为开发者提供方便的开发环境和开发工具,使得开发者能够更快速、更高效地进行STM32F103C8T6的开发工作。使用STM32F103C8T6 HAL库,开发者可以通过简单的函数调用来实现各种功能,如点亮LED灯、控制定时器、发送和接收串口数据等。 此外,还有一份基础开发教程,其中包括了配置开发环境、使用Keil进行开发、点亮LED灯、控制定时器、串口通信和使用传感器等内容。这些教程可以帮助开发者快速入门STM32F103C8T6的开发,掌握HAL库的使用方法。 如果你需要获取STM32F103C8T6 HAL库和相关的教程,你可以在文章末尾下载压缩包并解压,然后在Keil中导入STM32F103Pack包,或者直接从官方网站下载STM32CubeMX并安装,然后使用该软件生成你的第一个工程。同时,你还可以参考bsp.h头文件中的内容来初始化你的开发板。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [STM32F103C8T6 HAL库工程模板](https://download.csdn.net/download/qq_44744164/12918149)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [STM32F103C8T6基础开发教程(HAL库)—开发环境配置](https://blog.csdn.net/qq_38191568/article/details/126012144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [STM32F103C8T6移植uCOS基于HAL库](https://blog.csdn.net/weixin_46075497/article/details/121718285)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值