GPLO是通用输入/输出(General Purpose l/O)的简称,主要用于工业现场需要用到数字量输入/输出的场合,例如:
输出功能:继电器、LED、蜂鸣器等的控制
输入功能:传感器状态、高低电平等信息的读取
复用功能:片内外设的对外接口
时序模拟:模拟SPI、I2C等常用接口的时序
1.GPIO结构:
钳位电路:GPIO内部具有钳位保护二极管,其作用是防止从外部管脚Pin输入的电压过高或者过低。VDD正常供电是3.3V。如果从Pin输入的信号(假设任何输入信号都有一定的内阻)电压超过VDD加上二极管D1的导通压降(假定在0.7V左右),则二极管D1导通,会把多于的电流引到VDD,而真正输入到内部的信号电压不会超过4V。同理,如果从Pin输入的信最电压比GND还低,则由于二极管D2的作用,会把实际输入质部的信号电压钳制在-0.7V左右。
2.STM32F103有PA、PB、PC、PD和PE五个16位通用接口,每个GPIO端口有16个口线对应16个管脚,编号为0~15。每个 IO 口可以自由编程,但 IO口寄存器必须要按 32 位字被访问。
3.三种速度:
GPIO引脚速度:GPIO_Speed_2MHz (10MHz, 50MHz) ; ①2MHz②10MHz③50MHz
又称GPIO输出驱动电路响应速度(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。)
可理解为输出驱动电路的带宽:即一个驱动电路可以不失真地通过信号的最大频率。
如果一个信号的频率超过了驱动电路的响应速度,就有可能信号失真。
GPIO的引脚速度跟应用相匹配,速度配置越高,噪声越大,功耗越大。
带宽速度高的驱动器耗电大、噪声也大,带宽低的驱动器耗电小、噪声也小。使用合适的驱动器可以降低功耗和噪声。
高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配(推荐10倍以上)。
①USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小。
②I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度。
③SPI接口,若使用18M或9M波特率,需要选用50M的GPIO的引脚速度。
对翻转速度理解:
输入/输出寄存器的0 ,1值反映到外部引脚(APB2上)高低电平的速度.手册上指出GPIO最大翻转速度可达18MHz。
通过简单的程序测试,用示波器观察到的翻转时间: 是综合的时间,包括取指令的时间、指令执行的时间、指令执行后信号传递到寄存器的时间(这其中可能经过很多环节,比如AHB、APB、总线仲裁等),最后才是信号从寄存器传输到引脚所经历的时间。
如:有上拉电阻,其阻值越大,RC延时越大,即逻辑电平转换的速度越慢,功耗越大。
GPIO 输出速度:与程序有关,(程序中写的多久输出一个信号)。
①GPIO口设为输入时,输出驱动电路与端口是断开,所以输出速度配置无意义。
②在复位期间和刚复位后,复用功能未开启,I/O端口被配置成浮空输入模式。
③所有端口都有外部中断能力。为了使用外部中断线,端口必须配置成输入模式。
④GPIO口的配置具有上锁功能,当配置好GPIO口后,可以通过程序锁住配置组合,直到下次芯片复位才能解锁。
4.功能特性
在浮空/上拉/下拉模式时:
- 输出驱动器关闭
- 施密特触发器打开,可以获取引脚状态
- 通过寄存器使能上/下拉电阻:浮空/上拉/下拉输入
- 引脚电平状态将存入输入数据寄存器
在模拟输入时:
- 输出驱动器关闭
- 施密特触发器关闭、上/下拉电阻关闭
- 读输入数据寄存器的值为0
- 信号被送入AD模块
常见的ADC采集
每组GPIO端口的寄存器包括:
两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH)
两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR)
一个32位置位/复位寄存器(GPIOx_BSRR)
一个16位复位寄存器(GPIOx_BRR)
一个32位锁存寄存器(GPIOx_LCKR)
每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问)。
1.CRL/CRH每4位控制一个IO口,CRL控制标号0~7的口,CRH控制标号8~15的口
2.配置时,先配置MODE确定输入输出及端口速度,再配置CNF确定具体的输入/出模式,具体的上拉/下拉由PxODR寄存器决定。
1.IDR 是一个端口输入数据寄存器,只用了低 16 位,每个位控制该组IO的一个IO口,对应的是IO口的输入电平。该寄存器为只读寄存器,并且只能以16 位的形式读出。
1.ODR是一个端口输出数据寄存器,也只用了低16位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前IO口的输出状态。而向该寄存器写数据,则可以控制某个IO口的输出电平。
2.注:在输入模式下,通过该寄存器配置上拉还是下拉。
与BSRR寄存器的高16位几乎一样(时至20220928理解)
1.端口复用
2.端口重映射功能
3.所有IO口都可以作为中断输入
1.1个初始化函数:
void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
typedef struct
{
unit16_t GPIO_Pin;//指定要初始化的IO口
GPIOSpeed_TypeDef GPIO_Speed;//设置IO口输出速度
GPIOMode_Typedef GPIO_Mode;//设置工作模式:8种中的一个
}GPIO_InitTypeDef;
初始化样例
GPIOInitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOB,&GPIO_InitStructure);//根据设定参数初始化GPIOB.5
GPIO_Mode | 描述 |
---|---|
GPIO_Mode_AIN | 设置管脚工作模式为模拟输入 |
GPIO_Mode_IN_FLOATING | 设置管脚工作模式为浮空输入 |
GPIO_Mode_IPD | 设置管脚工作模式为输入下拉 |
GPIO_Mode_IPU | 设置管脚工作模式为输入上拉 |
GPIO_Mode_OUT_OD | 设置管脚工作模式为开漏输出 |
GPIO_Mode_OUT_PP | 设置管脚工作模式为推挽输出 |
GPIO_Mode_AF_OD | 设置管脚工作模式为复用的开漏 |
GPIO_Mode_AF_PP | 设置管脚工作模式为复用的推挽 |
2.2个读取输入电平函数:
unit8_t GPIO_ReadInputDataBit(GPIO_Typedef*GPIOx,unit16_t GPIO_Pin);
//作用:读取某个GPIO的输入电平,实际操作的是GPIOx_IDR寄存器
GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5);//读取GPIOA组中所有IO口的电平
unit16_t GPIO_ReadOutputData(GPIO_TypeDef*GPIOx);
//作用:读取某个GPIO的输入电平,实际操作的是GPIOx_IDR寄存器
GPIO_ReadOutputData(GPIOA);//读取GPIOA组中所有IO口的电平
3.2个读取输出电平函数
unit8_t GPIO_ReadOutputDataBit(GPIO_TypeDef*GPIO,unit16_t GPIO_Pin);
unit16_t GPIO_ReadOutputData(GPIO_TypeDef*GPIO);
4.4个设置输出电平函数
void GPIO_SetBits(GPIO_TypeDef*GPIOx,unit16_t GPIO_Pin);
//作用:设置某个IO口输出为高电平,实际操作BSRR寄存器
void GPIO_ResetBits(GPIO_TypeDef*GPIOx,unit16_t GPIO_Pin);
//作用:设置某个IO口输出为低电平,实际操作BRR寄存器
void GPIO_WriteBit(GPIO_TypeDef*GPIOx,unit16_t GPIO_Pin,BitAction BitVal);
void GPIO_Write(GPIO_TypeDef*GPIOx,unit16_t PortVal);
//这两个函数不常用,也是用来设置IO口输出电平
5.头文件中,使用
#ifndef
#define
#endif
条件编译,避免头文件内容重复定义。
注:或运算: A ∣ = B ⟹ A = A ∣ B A|=B\implies A=A|B A∣=B⟹A=A∣B
1.位操作基本原理:把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说BSRR奇存器有32个位,那么可以映射到32个地址,我们去访问(读-改-写)这32个地址就达到访问32个比特的目的。
2.哪些区域支持位操作:
其中一个是 SRAM 区的最低1MB范围:0x20000000- 0x200FFFFF (SRAM 区中的最低1MB)
第二个则是片内外设区的最低1MB范围:0x40000000 - 0x400FFFFF(片上外设区中最低1MB)
IO口操作的总结:
①对该IO口时钟初始化
②初始化IO口的模式
③对IO口输入/出进行控制(库函数/寄存器/位操作)
蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
1.我的STM32开发板板载的蜂鸣器是电磁式的有源蜂鸣器
这里的有源不是指电源的“源”,而是指有没有自带震荡电路,有源蜂鸣器自带了震荡电路,一通电就会发声;无源蜂鸣器则没有自带震荡电路,必须外部提供2~5Khz左右的方波驱动,才能发声。
2.需要注意的是:IO口的电流驱动能力是很有限的,所有一般不能通过IO口直接驱动大功率器件。
如图所示,使用三极管S8050来驱动蜂鸣器(利用了三极管电流放大作用)。
R33作用:在STM32复位后,IO口引脚默认浮空,浮空状态下,IO口产生跳变的电压可能会使蜂鸣器“嘀~嘀~”响,通过R33下拉电阻使得小电流直接通过R33接地,只有电流达到一定程度才会通过三极管放大。
1.关于按键的扫描方式:
①支持连续按:按下不松开,一直会检测到有效信号
②不支持连续按:按下不松开,只能检测到一次有效信号
故而可以联想到C语言关键字static
int getValue(void)
{
int flag=0;
flag++;
return flag;
}
返回的值每次都为1,因为每次执行这个函数,flag都会初始化为0,没有记忆功能
int getValue(void)
{
static int flag=0;
flag++;
return flag;
}
返回的值每次都加1,static有记忆功能
2.按键扫描函数的理解:
key_up=1表示按键按下,key_up=0表示按键松开
如果支持连按则会一直检测按键按下的脉冲,反之则只会检测一次
运算符 | 含义 | 运算符 | 含义 |
---|---|---|---|
& | 按位与 | ~ | 取反 |
| | 按位或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
GPIOA->CRL&=0xFFFFFF0F;//将4~7位清0
GPIOA->CRL|=0x00000040;//设置相应位的值
GPIOA->ODR|1<<5; //将ODR寄存器的第5位设置为1
TIMx->SR=(unit16_t)~TIM_FLAG;
1.define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。
常见格式:#define 标识符 字符串
“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串。
2.ifdef条件编译(时至20220930不理解)
单片机程序开发过程中,经常会遇到一种情况,当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。条件编译命令最常见的形式为:
#ifdef 标识符
程序段1
#else
程序段2
#endif
1.C语言中extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。
2.注:对于extern申明变量可以多次,但定义只有一次。
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。
typedef unsigned int unit32_t;//将unsigned int替换为unit32_t
typedef unsigned char unit8_t;
typedef unsigned short int unit16_t;
Struct 结构体名{
成员变量1;
成员变量2;
...
}变量名列表
在结构体申明的时候可以定义变量,也可以申明之后定义,方法是:Struct 结构体名字 结构体变量列表;
同一个类型可以用数组,不同类型可以用结构体组织。结构体可扩展性强。
对MCU,一切底层配置,最终都是配置寄存器。
感觉迷迷瞪瞪似懂非懂的(时至20221006不理解)
1.STM32有5个时钟源:HSI、HSE、LSI、LSE、PLL.
2.系统时钟SYSCLK可来源于三个时钟源:
3.STM32可以选择—个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、 HSI、HSE、或者系统时钟。
4.任何一个外设在使用之前,必须首先使能其相应的时钟。
5.RCC相关头文件和固件库源文件
头文件:stm32f10x_rcc.h
源文件:stm32f10x_rcc.c
RCC_LSEConfig();
RCC_HSEConfig();
RCC_HSICmd();
RCC_LSICmd();
RCC_PLLCmd();
RCC_PLLConfig();
RCC_SYSCLKConfig();
RCC_RTCCLKConfig();
RCC_HCLKConfig();
RCC_PCLK1Config();
RCC_PCLK2Config();
RCC_APB1PeriphClockCmd();//APB1线上外设时钟使能
RCC_APB1PeriphClockCmd();//APB2线上外设时钟使能
RCC_AHBPeriphClockCmd();//AHB线上外设时钟使能
RCC_ADCCLKConfig();
RCC_GetClocksFreq();
RCC_GetSYSCLKSource();
RCC_GetFlagStatus();
RCC_ITConfig();
RCC_GetITStatus();
RCC_ClearITPendingBit();
6.RCC相关配置寄存器
typedef struct
{
__IO uint32_t CR;//HSL,HSE,,CSS,PLL等的使能和就绪标志位
__IO uint32_t CFGR;//PLL等的时钟源选择,分频系数设定
__IO uint32_t CIR;//清除/使能 时钟就绪中断
__IO uint32_t APB2RSTR;//APB2线上外设复位寄存器
__IO uint32_t APB1RSTR;//APB1线上外设复位寄存器
__IO uint32_t AHBENR;//DMA,SDIO等时钟使能
__IO uint32_t APB2ENR;//APB2线上时钟使能
__IO uint32_t APB1ENR;//APB1线上时钟使能
__IO uint32_t BDCR;//备份域控制寄存器
__IO uint32_t CSR;//控制状态寄存器
}RCC_TypeDef
7.时钟系统初始化函数剖析(部分)
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit等待振荡器稳定 */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;//判断HSE时钟就绪
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
//这三行代码的原因是因为CPU的速度是比FLASH的速度快很多的
/* Flash 2 wait state,通过查看手册对ACR寄存器介绍,如果系统时钟在48~72MHz范围内,需要两个等待状态 */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK AHB预分频器设置为1*/
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK APB2预分频器设置为1*/
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK/2 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
//STM32F103ZET6为大容量芯片HD,所以这一段不用看,直接看else
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
8.小问题:为什么在main函数中,不调用SystemInit();函数却可以使能时钟呢?
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
通过上面这段代码(用汇编语言写的)可知,在系统复位之后,会先执行SystemInit();函数,再执行main();函数。
1.对于CM3、CM4 内核的处理器,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。利用 STM32 的内部 SysTick 来实现延时的,这样既不占用中断,也不占用系统定时器。一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。
2.SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常。(时至20221006不理解)
1.Systick控制和状态寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
16 | COUNTFLAG | R | 0 | 如果在上次读取本寄存器后,Systick已经数到了0,则该位为1,如果读取该位,该位自动清零 |
2 | CLKSOURCE | R/W | 0 | 0=外部时钟源(STCLK)、1=内核时钟(FCLK) |
1 | TICKINT | R/W | 0 | 1=Systick倒数到0时产生Systick异常请求、0=数到0时无动作 |
0 | ENABLE | R/W | 0 | Systick定时器的使能位 |
2.对于STM32,外部时钟源是HCLK(AHB总线时钟的1/8,内核时钟是HCLK时钟)
配置函数:Systick_CLKSourceConfig();
3.SysTick重装载数值寄存器-LOAD
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23:0 | RELOAD | R /W | 0 | 当倒数至零时,将被重装载的值 |
4.SysTick当前值寄存器-VAL
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23:0 | CURRENT | R/Wc | 0 | 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志 |
5.固件库中的Systick相关函数:
SysTick_CLKSourceConfig();//Systick时钟源选择(misc.c文件中)
SysTick_Config(unit32_t ticks);//初始化systick,时钟为HCLK,并开启中断(core_cm3.h/core_cm4.h文件中)
6.Systick中断服务函数
void SysTick_Handler(void);
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
#endif
}
1.在操作系统中充当系统“心跳”
void InitSysTick()
{
if(SysTick_Config(SystemCoreClock/1000))//1ms
{
while(1);
}
}
//在system_stm32f10x.c文件中:
#elif define SYSCLK_FREQ_72MHz
unit32_t SystemCoreClock=SYSCLK_FREQ_72MHz;
void SysTick_Handler(void)
{
OSIntEnter();//进入中断
OSTimeTick();//调用ucos的时钟服务程序
OSIntExit();//触发任务切换软中断
}
1.三种STM32定时器区别
定时器种类 | 位数 | 计数器模式 | 产生DMA请求 | 捕获/比较通道 | 互补输出 | 特殊应用场景 |
---|---|---|---|---|---|---|
高级定时器(TIM1,TIM8) | 16 | 向上,向下,向上/下 | 可以 | 4 | 有 | 带死区控制盒紧急刹车,可应用于PWM电机控制 |
通用定时器(TIM2~TIM5) | 16 | 向上,向下,向上/下 | 可以 | 4 | 无 | 通用。定时计数,PWM输出,输入捕获,输出比较 |
基本定时器(TIM6,TIM7) | 16 | 向上,向下,向上/下 | 可以 | 0 | 无 | 主要应用于驱动DAC |
2.通用定时器功能特点描述
3.计数器模式
4.通用定时器工作过程
计数器时钟可以由下列时钟源提供:
①内部时钟(CK_INT)
默认调用Systemlnit函数情况下:
SYSCLK=72M
AHB时钟=72M
APB1时钟=36M
所以APB1的分频系数=AHB/APB1时钟=2。所以,通用定时器时钟CK_INT=2*36M=72M
②外部时钟模式1:外部输入脚(TIx)
③外部时钟模式2:外部触发输入(ETR)
④内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
5.定时器中断实验相关寄存器
6.常用库函数
void TIMx_TimeBaseInit(TIM_TypeDef*TIMx,TIMx_TimeBaseInitTypeDef*TIMx_TimeBaseInitStruct);
typedef struct
{
//预分频系数
uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
//计数模式
uint16_t TIM_CounterMode; /*!< Specifies the counter mode.
This parameter can be a value of @ref TIM_Counter_Mode */
//自动装载值
uint16_t TIM_Period; /*!< Specifies the period value to be loaded into the active
Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF. */
uint16_t TIM_ClockDivision; /*!< Specifies the clock division.
This parameter can be a value of @ref TIM_Clock_Division_CKD */
uint8_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter
reaches zero, an update event is generated and counting restarts
from the RCR value (N).
This means in PWM mode that (N+1) corresponds to:
- the number of PWM periods in edge-aligned mode
- the number of half PWM period in center-aligned mode
This parameter must be a number between 0x00 and 0xFF.
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;
void TIM_Cmd(TIM_TypeDef*TIMx,FunctionalState NewState);
void TIM_ITConfig(TIM_TypeDef*TIMx,unit_16 TIM_IT,FunctionalState NewState);
s TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
7.定时器中断实现步骤
RCC_APB1PeiphClockCmd();
TIM_TimeBaseInit();
void TIM_ITConfig();
NVIC_Init();
TIM_Cmd();
TIMx_IRQHandler();