历史上的今天
返回首页

历史上的今天

今天是:2025年02月24日(星期一)

正在发生

2020年02月24日 | 嵌入式STM32学习笔记(2)——点亮LED灯及用中断让其闪烁

2020-02-24 来源:eefocus

这里直接开始码代码了,至于前期的准备工作比如配置MDK-keil,或配置IAR等,大家可以在网上找对应的教程,这里不赘述了;直接讲代码如何撸吧,代码里我做了详细注释:


1)编译器IAR8,系统win10;


2)板子:STM32F103C8T6核心板,如下:

3)下载器:ST-LINK/V2仿真下载器;


4)板子上LED对应的引脚是GPIOC, GPIO_Pin_13;在IAR对应的stm32F103X模板DRIVER目录下添加:led.c,led.h,timer.c,timer.h文件,如下:

5)led.c 代码如下:


#include "led.h"

 

/*LED_G 驱动 GPIO 初始化函数*/

void led_gpio_config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure; //调用GPIO结构体

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //配置RCC时钟,使得引脚使能

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //设置的引脚

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚速度

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚模式,推挽式输出

  GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化引脚

  

//  以下实验代码

//   GPIO_InitTypeDef  GPIO_InitStructure;

//

//   /* Enable the GPIO_LED Clock */

//   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB 

//                   |RCC_APB2Periph_GPIOC

//   |RCC_APB2Periph_GPIOD, ENABLE);//使能

//

//   /* Configure the GPIO_LED pin */

//   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

//   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

//   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//  

//   GPIO_Init(GPIOA, &GPIO_InitStructure);

//   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;

//   GPIO_Init(GPIOB, &GPIO_InitStructure);

//   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All ;

//   GPIO_Init(GPIOC, &GPIO_InitStructure);

   

}

6)led.h的代码:


#ifndef _LED_H

#define _LED_H

 

/*包含相关的头文件*/

#include "stm32f10x.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

 

void led_gpio_config(void);//声明,初始化LED对应引脚

 

#endif

7)timer.c代码:


#include "timer.h"

__IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化

__IO uint32_t TimingDelay2; //计数变量2

 

/*SystemCoreClock / 1000000  -------   1us*/

/*SystemCoreClock / 100000   -------   10us*/

/*SystemCoreClock / 10000    -------   100us*/

/*SystemCoreClock / 1000     -------   1ms*/

 

 

//////////////////////////

//设置系统滴答中断延时程序//

/////////////////////////

 

void Systick_Init(void)

{

  //装载系统时钟中断计数值,系统时钟累计达到72000时候溢出产生中断

    if (SysTick_Config(72000))

    { 

      /* Capture error */ 

      while (1);

    }

}

 

//延时计数函数,如果不是0,每个系统滴答中断周期自减

void TimingDelay_Decrement(void)

{

    if (TimingDelay != 0x00)

    {

        TimingDelay--;

    }

}

 

//延迟函数,设置为 US

void delay_ms(__IO uint32_t nTime)

{

    TimingDelay = nTime;//自减初始值

    while(TimingDelay != 0);

}

 

//中断事件函数,原函数在stm32f10x_it.c里面,复制到这里后要将原位置里的注释掉,不然报错

void SysTick_Handler(void)

{

    TimingDelay_Decrement();

}

 

//////////////////////////

//设置定时器中断延时程序//

/////////////////////////

 

//配置嵌套中断控制器 NVCI

void tim2_nvic_config(void)

{

    NVIC_InitTypeDef NVIC_Init_Struct; //调用NVCI结构体

    

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置组优先级

    

    NVIC_Init_Struct.NVIC_IRQChannel = TIM2_IRQn; //设置定时器 2 中断

    NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级

    NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 0; //设置子优先级

    NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断

    NVIC_Init(&NVIC_Init_Struct); //初始化NVIC

}

 

 

//定时器初始化配置

void tim2_config(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //调用定时器结构体

    

    tim2_nvic_config(); //加载嵌套中断控制器 NVCI

    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //配置RCC时钟,使得中断使能

    TIM_DeInit(TIM2); //将外设 TIMx 寄存器重设为缺省值,复位寄存器

    

    /*

定时计数计算方法如下:

发生中断时间 = (TIM_Prescaler+1)* (TIM_Period+1)/FLK

以定时 1s 为例 TIM_Period=2000-1, TIM_Prescaler=(36000-1)

    */   

    TIM_TimeBaseInitStruct.TIM_Prescaler = 36000-1; //时钟预先分频数

    TIM_TimeBaseInitStruct.TIM_Period = 2-1;  //自动重装载寄存器的值

    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,向上计数方式

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);    //初始化TIM2配置

    TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除溢出中断标志

    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIM 中断

    TIM_Cmd(TIM2,ENABLE); //开启时钟

}

 

 

//延时计数函数2,如果不是0,每个系统滴答中断周期自减

void TimingDelay_Decrement2(void)

{

    if (TimingDelay2 != 0x00)

    {

        TimingDelay2--;

    }

}

 

//延迟函数,设置为 US

void delay_ms2(__IO uint32_t nTime2)

{

    TimingDelay2 = nTime2;//时钟滴答数

    while(TimingDelay2 != 0);

}

 

 

//定时器2,中断事件函数

void TIM2_IRQHandler(void)

{

    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//固件库函数,判断是否发生TIM2中断

    {

      TimingDelay_Decrement2(); //调用延时计数函数

    }

    TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//标志位清除,固件库函数

}

 

8)timer.h代码:


#ifndef __TIMER_H_

#define __TIMER_H_

 

#include "stm32f10x_tim.h"

#include "stm32f10x_rcc.h"

#include "stm32f10x_it.h"

#include "misc.h"

 

extern __IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化

void Systick_Init(void); //初始化系统滴答

void TimingDelay_Decrement(void); //计数函数

void delay_ms(__IO uint32_t nTime);//延迟函数,设置为 US

 

 

extern __IO uint32_t TimingDelay2; //计数变量2

void tim2_nvic_config(void); //初始化中断

void tim2_config(void); //初始化计数器

void delay_ms2(__IO uint32_t nTime2);//延迟函数2,设置为 US

void TimingDelay_Decrement2(void); //计数函数2

 

#endif

9)主函数main.c代码:


#include "led.h"

#include "timer.h"

 

int main(void)

{

    SystemInit();  //初始化系统时钟

    Systick_Init(); //配置系统时钟滴答参数

    led_gpio_config();  //配置GPIO

    tim2_config();//配置定时器

    

    while(1)

    {

      

      //调用系统滴答延时函数做LED灯的闪烁//

//        GPIO_SetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成高电平

//        delay_ms(100);                    //调用系统滴答延时函数

//        GPIO_ResetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成低电平

//        delay_ms(100);                       //调用系统滴答延时函数

      

        //调用定时器延时函数做LED灯闪烁//

        GPIO_SetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成高电平

        delay_ms2(500);                     //调用定时器延时函数

        GPIO_ResetBits(GPIOC, GPIO_Pin_13);   //将PB13设置成低电平

        delay_ms2(100);                     //调用定时器延时函数      

    }

    return 0;

}

推荐阅读

史海拾趣

Aten International公司的发展小趣事

在电子设备的日益增多的背景下,用户对于高效、便捷的设备管理需求愈发强烈。Aten International凭借其对连接技术的深入理解,成功研发出KVM切换器,该产品能够实现对多台计算机的控制,大大提高了工作效率。随着技术的不断进步,Aten International的KVM切换器不断更新迭代,从最初的简单切换功能,发展到现在的智能管理、远程操控等高级功能,成为了电子行业的一大亮点。

AMS公司的发展小趣事

随着业务的不断发展,Aten International开始积极拓展全球市场。通过与国际知名企业的合作,Aten International成功将其产品和服务推广至全球各地。同时,公司还设立了多个海外分支机构和办事处,以便更好地服务全球客户。这一举措不仅提升了Aten International的品牌影响力,也为公司的持续发展奠定了坚实基础。

Datalinear公司的发展小趣事

在国内市场取得成功后,Datalinear公司开始寻求国际化的发展。公司派遣团队前往欧美等发达国家进行市场调研,并根据当地市场需求进行产品定制。通过不懈的努力,Datalinear公司的产品在海外市场取得了良好的销售业绩,并逐步建立了全球化的销售网络。

Apex Tool Group公司的发展小趣事

在国内市场取得成功后,Datalinear公司开始寻求国际化的发展。公司派遣团队前往欧美等发达国家进行市场调研,并根据当地市场需求进行产品定制。通过不懈的努力,Datalinear公司的产品在海外市场取得了良好的销售业绩,并逐步建立了全球化的销售网络。

Charcroft Electronics Ltd公司的发展小趣事

在竞争激烈的电子行业中,供应链管理是企业成功的关键之一。Charcroft Electronics Ltd公司注重优化供应链管理,通过与供应商建立长期稳定的合作关系,确保原材料的质量和供应的稳定性。同时,公司还采用先进的供应链管理技术,实现库存的精准控制和物流的高效运作,提高了运营效率和市场响应速度。

Collins Electronics Corp公司的发展小趣事

随着公司规模的扩大,Collins Electronics Corp开始将目光投向国际市场。他们积极参加国际电子展会,与世界各地的潜在客户和合作伙伴交流。通过与不同国家的企业合作,公司成功打入了国际市场,产品销量大幅提升。这一过程中,他们不仅学习了国际先进的电子技术,还积累了丰富的跨国运营经验。

问答坊 | AI 解惑

讨论模拟电源与数字电源/模拟地与数字地

关于模拟电源与数字电源,模拟地与数字地的大家有什么高见呢? 在网上看过一些关于这个问题的谈论,但是还不是太明白. 就是模拟电源与数字电源,模拟地与数字地应该怎么连接的问题. 首先是模拟电源与数字电源的连接,一些人说应该在电源接入处用粗线 ...…

查看全部问答>

实用工具

本帖最后由 paulhyde 于 2014-9-15 09:23 编辑 …

查看全部问答>

高手请教,如何定位主函数起始地址!

我用C写源代码,那MSP430还要写BOOTSTRAP LOADER的程序,bootstrap loader程序是写了以便于PC机将应用程序的代码烧至MCU上,请问MSP430如何判断并从我设定的主程序起始地址开始执行我的应用主程序,在C语言程序里该怎么写这个呢?请高手帮忙解答一 ...…

查看全部问答>

报名《全民DIY实验电源》硬件原理图

还好赶在11.25之前完成。各路英雄及版主,请好好指教指教,谢谢。               电源输入:     PFC部分:     辅助电源部分:   主电源初级:   其 ...…

查看全部问答>

BKP_ClearFlag与 BKP_GetITStatus 函数区别

求高手指点下STM32 中 BKP_ClearFlag()与 BKP_GetITStatus () 的区别。 固件库使用手册这么说的:   函数原形  ITStatus BKP_GetITStatus(void)  功能描述  检查侵入检测中断发生与否   函数原形  void BKP_Cl ...…

查看全部问答>

易电源心得体会

刚开始感觉一定会很难  结果挺简单的  基本的电路知识就能使用易电源方便开发 …

查看全部问答>

谁有四旋翼飞行器的资料

本帖最后由 paulhyde 于 2014-9-15 03:23 编辑 谁有四旋翼飞行器的资料    …

查看全部问答>

电子电路好书推荐---综合电子系统设计与实践

本帖最后由 tiankai001 于 2014-6-5 07:13 编辑 综合电子系统设计与实践 为高等学校电子信息类专业编写的一本综合性电子设计的实践类教材。以电子系统设计方法为主线,将模拟系统设计、数字系统设计、单片机应用系统设计,以及传感器与控制等 ...…

查看全部问答>

将运算放大器用作比较器,您觉得可行吗?

将运算放大器用作比较器可行吗? 一般而言,当您只需要一个简单的比较器,并且您在四运算放大器封装中还有一个“多余”运算放大器时,这种做法是可行的。稳定运算放大器运行所需的相位补偿意味着把运算放大器用作比较器时其速度会非常的低,但是如 ...…

查看全部问答>