STM32基础设计(7)---时钟中断(控制LED灯)

发布者:Jinyu521最新更新时间:2019-01-29 来源: eefocus关键字:STM32  时钟中断  控制LED灯 手机看文章 扫描二维码
随时随地手机看文章

本文将介绍STM32的基础时钟,通过时钟中断来控制LED灯的亮灭。


本文的大致思路如下:


1,LED的GPIO口初始化


2,中断初始化


3,时钟初始化


4,编写中断函数


5,编写主函数


首先讲下笔者在做这个设计时得到的教训:


        笔者最初是用TIM6基础时钟来实现设计功能,在编写完代码后发现,灯不亮,于是笔者就开始整问题了。先看看代码有没有编写错误,检查一遍后,中断通道使用正确,TIM6配置正确,LED灯的串口也没有问题,中断函数也正常编写了。然后笔者纠结了,他妈代码全对了怎么就运行失败?(原谅笔者爆粗口,因为当时心情的确很不好,可以想象一下,辛辛苦苦桥的代码,没什么毛病,结果到了板子上还运行不了)之后笔者认认真真核对代码,还是没解决问题,之后没办法了,去论坛上请教大佬去了,(还是大佬厉害)我把问题说了后,大佬看了后说,可能是你的启动文件里没有TIM6中断(笔者顿悟了),他妈我怎么没想到这个。。。之后去检查发现果然没有这个中断函数入口(STM32中必须按照要求写中断函数名才能进入中断),之后笔者发现我的工程中定义的是STM32F10X_MD这个头文件,这个头文件里没有TIM6这个中断名(当初笔者也发现了这个问题,自己看定义了个#define 54(因为我查了其他头文件是54)),又检查了启动文件,发现没有写中断函数入口,笔者就把TIM6换成TIM3(通用定时器)了,之后就正常了。希望可以帮助到和我犯同样错误的人。


下面进入主题,详细解释代码:


1,LED的GPIO口初始化

void led_init()

{

GPIO_InitTypeDef led_gpio;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO,ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);因为GPIOC13口的13引脚被重映射了,所以需要先关闭重映射

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

led_gpio.GPIO_Pin = GPIO_Pin_13;

led_gpio.GPIO_Mode = GPIO_Mode_Out_PP;

led_gpio.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&led_gpio);

}

2,中断初始化

void nvic_init()

{

NVIC_InitTypeDef nvic;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);定义分组

nvic.NVIC_IRQChannel  =TIM3_IRQn;中断通道名

nvic.NVIC_IRQChannelPreemptionPriority = 1;

nvic.NVIC_IRQChannelSubPriority = 0;

nvic.NVIC_IRQChannelCmd= ENABLE;中断时能

NVIC_Init(&nvic);初始化寄存器

}

3,时钟初始化

void tim_init()

{

TIM_TimeBaseInitTypeDef tim;定义时钟结构体

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);时能TIM3

tim.TIM_Period = 1000-1;计数周期

tim.TIM_Prescaler = 72 - 1;预分频数

tim.TIM_ClockDivision = TIM_CKD_DIV1;时钟分频,设置定时器时钟CK_INT频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能

tim.TIM_CounterMode = TIM_CounterMode_Up;定时器基础方式,可以是向上计数、向下计数、中心对其模式。基本定时器只能是向上计数。

tim.TIM_RepetitionCounter = 0;重复计数器,属于高级控制寄存器专用寄存器位,这里不用设置。

TIM_TimeBaseInit(TIM3,&tim);初始化

TIM_ClearFlag(TIM3,TIM_FLAG_Update);清除中断标志

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);开启中断

TIM_Cmd(TIM3,ENABLE);TIM3使能

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,DISABLE);关闭TIM3时钟,等需要时在打开

}

4,编写中断服务函数

void TIM3_IRQHandler()

{

if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET){判断是否可以中断

//PrintString("\r\ntime inter");这个是笔者在调试程序时用的串口

time++;

if(time >=1000)实现1秒一计数

{

//PrintString("\r\nin time inter");

time = 0;以下是实现灯的亮灭

if(GPIOC->ODR & GPIO_Pin_13)

{

GPIOC->BRR = GPIO_Pin_13;

}else

{

GPIOC->BSRR = GPIO_Pin_13;

}

}

}

TIM_ClearITPendingBit(TIM3,TIM_FLAG_Update);清除中断标志位避免重复进入中断

}


5,主函数

int main()

{

led_init();LED初始化

tim_init();时钟初始化

nvic_init();中断初始化

//nvic_usart_init();

//usart_init();

GPIOC->BSRR = GPIO_Pin_13;预先打开灯

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);使能TIM3

delay(1000);延时1秒

while(1){死循环

//PrintString("\r\nÑ­»·");

}

}


下面粘贴详细代码:


注:注释掉的部分是笔者用串口在调试程序,可忽略(笔者经验有限,如有不妥之处请指教)


#include

static unsigned int time;

uint8_t TxCount=0;

uint8_t Count=0;

static uint8_t TxBuff[256];

void delay(uint16_t n)

{

int i,j;

for(i=0;i

for(j=0;j<8500;j++);

}

void tim_init()

{

TIM_TimeBaseInitTypeDef tim;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

tim.TIM_Period = 1000-1;

tim.TIM_Prescaler = 71;

tim.TIM_ClockDivision = TIM_CKD_DIV1;

tim.TIM_CounterMode = TIM_CounterMode_Up;

tim.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(TIM3,&tim);

TIM_ClearFlag(TIM3,TIM_FLAG_Update);

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);

TIM_Cmd(TIM3,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,DISABLE);

}

void PrintU8(uint8_t data)

{

TxBuff[TxCount++]=data;

if(!(USART1->CR1 & USART_CR1_TXEIE))

{

USART_ITConfig(USART1,USART_IT_TXE,ENABLE);

}

}

 

void PrintString(uint8_t *s)

{

uint8_t *p;

p=s;

while(*p != '\0')

{

PrintU8(*p);

p++;

}

}

void usart_init()

{

GPIO_InitTypeDef Uart_A;  

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 

Uart_A.GPIO_Pin = GPIO_Pin_9;  

    Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  

    Uart_A.GPIO_Mode = GPIO_Mode_AF_PP;  

    GPIO_Init(GPIOA,&Uart_A);  

      

    Uart_A.GPIO_Pin = GPIO_Pin_10;  

    Uart_A.GPIO_Speed = GPIO_Speed_50MHz;  

    Uart_A.GPIO_Mode = GPIO_Mode_IN_FLOATING; //page 110  

    GPIO_Init(GPIOA,&Uart_A);  

USART_InitTypeDef Uart;  

      

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  

    Uart.USART_BaudRate = 115200;  

    Uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  

    Uart.USART_Mode = USART_Mode_Tx;  

    Uart.USART_Parity = USART_Parity_No;  

    Uart.USART_StopBits = USART_StopBits_1;  

    Uart.USART_WordLength = USART_WordLength_8b;  

    USART_Init(USART1,&Uart);  

      

    USART_Cmd(USART1,ENABLE);  

    USART_ClearFlag(USART1,USART_FLAG_TC);

}

void nvic_usart_init()

{

NVIC_InitTypeDef nvic;  

      

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  

      

    nvic.NVIC_IRQChannelPreemptionPriority = 0;  

    nvic.NVIC_IRQChannelSubPriority = 0;  

    nvic.NVIC_IRQChannel = USART1_IRQn;  

    nvic.NVIC_IRQChannelCmd = ENABLE;  

    NVIC_Init(&nvic);  

}

void nvic_init()

{

NVIC_InitTypeDef nvic;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

nvic.NVIC_IRQChannel  =TIM3_IRQn;

nvic.NVIC_IRQChannelPreemptionPriority = 1;

nvic.NVIC_IRQChannelSubPriority = 0;

nvic.NVIC_IRQChannelCmd= ENABLE;

NVIC_Init(&nvic);

}

void led_init()

{

GPIO_InitTypeDef led_gpio;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO,ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

led_gpio.GPIO_Pin = GPIO_Pin_13;

led_gpio.GPIO_Mode = GPIO_Mode_Out_PP;

led_gpio.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&led_gpio);

}

int main()

{

led_init();

tim_init();

nvic_init();

//nvic_usart_init();

//usart_init();

GPIOC->BSRR = GPIO_Pin_13;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

delay(1000);

while(1){

//PrintString("\r\nÑ­»·");

}

}

void TIM3_IRQHandler()

{

if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET){

//PrintString("\r\ntime inter");

time++;

if(time >=1000)

{

//PrintString("\r\nin time inter");

time = 0;

if(GPIOC->ODR & GPIO_Pin_13)

{

GPIOC->BRR = GPIO_Pin_13;

}else

{

GPIOC->BSRR = GPIO_Pin_13;

}

}

}

TIM_ClearITPendingBit(TIM3,TIM_FLAG_Update);

}

void USART1_IRQHandler(void)

{

if(USART1->SR & USART_SR_TC) 

    {  

        USART1->DR = TxBuff[Count++]; 

        if(TxCount == Count) 

        {  

            USART1->CR1 &= ~USART_CR1_TXEIE;  

        }  

    }  

}


关键字:STM32  时钟中断  控制LED灯 引用地址:STM32基础设计(7)---时钟中断(控制LED灯)

上一篇:通过库函数使用STM32f103串口中断的心得
下一篇:STM32基础设计(5)---ADC转换(中断方式)

推荐阅读最新更新时间:2024-03-16 16:23

STM32 RTC设置
RTC配置: 1.打开电源管理和备份寄存器时钟。这个在RCC配置中打开。 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); 2.使能RTC和备份寄存器的访问(复位默认关闭)。 PWR_BackupAccessCmd(ENABLE); 3.检查电池是否断电过(是否RTC初始化过),通过的话直接跳到第4步。 if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) { A. BKP_DeInit();//BKP寄存器全部设为缺省值 B. RCC_LSEConfig(RCC_LS
[单片机]
STM32学习记录12 中断向量表
从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例如: AREA RESET, DATA, READONLY ; 定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000) EXPORT __Vectors IMPORT OS_CPU_SysTickHandler IMPORT OS_CPU_PendSVHandler __Vectors DCD __initial_sp ; Top of Stack DCD Reset_
[单片机]
<font color='red'>STM32</font>学习记录12 中断向量表
stm32串口中断接收一帧数据
最近用到stm32的串口,中断一个字符一个字符接收好心累,网上度了一下发现了一篇好的帖子,和大家分享一下,原贴地址:http://www.51hei.com/bbs/dpj-39885-1.html 再次感谢原贴楼主的分享,为了方便大家,我把原文复制过来》 今天说一下STM32单片机的接收不定长度字节数据的方法。由于STM32单片机带IDLE中断,所以利用这个中断,可以接收不定长字节的数据,由于STM32属于ARM单片机,所以这篇文章的方法也适合其他的ARM单片机。 IDLE中断什么时候发生? IDLE就是串口收到一帧数据后,发生的中断。什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据
[单片机]
<font color='red'>stm32</font>串口中断接收一帧数据
STM32GPIO外部中断的详细解析和总结
1 STM32中断分组 STM32 的每一个GPIO都能配置成一个外部中断触发源,这点也是 STM32 的强大之处。STM32 通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB0,PC0,PD0,PE0,PF0,PG0为第一组,那么依此类推,我们能得出一共有16 组,STM32 规定,每一组中同时只能有一个中断触发源工作,那么,最多工作的也就是16个外部中断。STM32F103 的中断控制器支持 19 个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F103 的19 个外部中断为: 线 0~15:对应外部 IO 口的输入中断。 线 16:连接到 PVD 输出。 线
[单片机]
STM32GPIO外部中断的详细解析和总结
STM32库函数和寄存器操作的思考
从开始接触51单片机,到现在开始转型学习功能更加强大的STM32f407系列, 学习过程中引入了库函数及相应操作,当时赶着进度做点东西出来,有点不求甚解。现在返回来求索:相比于原来51单片机的寄存器,32系列的寄存器无论是个数还是实现功能时多个寄存器之间的调用配合,使用难度都高了不少,所以有了库函数和相应的固件库来减少难度。 先说一下固件库(这个我们最开始安装完MDK缺了它总是各种报错的东西)和相应库函数: 固件库这边时首先将各个设备所有寄存器的配置字进行预定义,然后封装在结构体或者枚举变量中,等到用户调用相关库函数时,会根据用户传入的参数从这些已经封装好的结构体或者枚举变量中取出与之对应的配置字,最后写入相应寄存器中完成对底层寄
[单片机]
基于STM32单片机的火控系统信号采集测试
火控系统是控制火炮瞄准和发射的系统,火控计算机是火控系统的核心,在完成火控解算进而引导高炮射击时具有重要作用。由于火控系统信号众多,状态复杂,对其关键信号的采集测试就显得尤为重要 . 普通信号采集测试装置具有结构复杂、造价昂贵、携带不便等特点,该方案结合最新型ARMv7系列STM32单片机,利用其丰富的外设接口和I/O资源,对某型火控系统的重点输出信号进行采集,存入板载Flash以备使用。另外,为便于使用和调试,还设计了CAN接口和RS-232串口。该信号采集盒大小为100 mm×65 mm,可由被测板提供电源信号,具有携带方便、使用简单的特点,对装备信号的实时采集具有重要的实用意义。 1总体设计方案 1.1总体设计框图
[单片机]
基于<font color='red'>STM32</font>单片机的火控系统信号采集测试
STM32 结构体位域操作 (int a:4)
1、什么是位域 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。 例如: 在存放一个开关量时,只有 0 和 1 两种状态, 用一位二进位即可。 为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。 所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。 每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。 位段成员必须声明为 int、unsigned int 或 signed int 类型(short char long)。 2、位域定义 struct
[单片机]
STM32 SysTick中断使用方法
SysTick中断属于核内外设中断器,中断号为-1。想要使用SysTick中断,只需在SysTick查询定时上进行稍微的修改。需要添加开启中断,直接用中断函数对计数标志位进行清零,不再使用查询方式判断计数是否结束去清零。中断函数接口SysTick_Handler在汇编文件中已经给出定义,直接到文件中查找即可。 本来NVIC提供了中断使能的函数,但是要求中断号要大于0(Value cannot be negative.),所以就不能调用NVIC中断使能函数了,直接在操作寄存器开启中断就可以了。 修改如下: #include delay.h #include led.h void Systick_Delayus
[单片机]
<font color='red'>STM32</font> SysTick中断使用方法
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved