stm32常见外设初始化步骤(GPIO、EXTI、TIM、TIM OC、TIM IC、ADC)

害,真的是忙里偷闲啊,这段时间临近multiple ddls,好久没更新了,水一篇stm32的。

几种常用外设的初始化示例

也是顺便存个档

GPIO

void my_GPIO_Init()
{
	/* GPIO */
	//RCC开启GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//结构体初始化GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	// 推挽输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3;	// 开启引脚
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;	// 所选pin脚的速度
	GPIO_Init(GPIOA, &GPIO_InitStruct);
}

EXTI

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更紧急的中断源

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

Extern Interrupt-外部中断

EXTI可以监测指定GPIO口的电平信号,电平变化时EXTI立即向NVIC发出中毒那申请,经NVIC裁决发送CPU。即引脚电平变化——》申请中断

支持的触发方式:上升沿/下降沿/双边沿/软件触发

支持的GPIO口:all,但是相同pin口不能同时触发中断(GPIOA和GPIOB的pin3口不能同时触发)

通道数:16个GPIO_Pin,+PVD输出,RTC闹钟,USB唤醒,以太网唤醒

触发响应方式:中断响应(触发CPU)/事件响应(触发别的外设)

中断执行流程:

中断代码封装在一个子函数里,由硬件在符合中断条件的时候自动调用,不需要我们在代码中调用。

void my_EXTI_Init()
{
	/* RCC */
	//开启GPIOB和AFIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /* GPIO */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    /* AFIO */
    // 配置中断源
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
    
    /* EXTI */
    EXTI_InitTypeDef EXTI_InitStruct;
    EXTI_InitStruct.EXTI_Line = EXTI_Line14;                // EXTI的14th通道
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;        // 配置成中断触发
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;    // 下降沿触发
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;                  // 开启
    EXTI_Init(&EXTI_InitStruct);
    
    /* NVIC */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        	// 优先级分组
    NVIC_InitTypeDef NVIC_InitStruct;					    // 结构体初始化NVIC 
    NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;		// 选择中断请求通道 
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;			// 使能
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; 	// 配置抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;			// 配置响应优先级
    NVIC_Init(&NVIC_InitStruct);
}

TIM(普通定时器)

TIM(Timer)定时器

定时器可以对输入的时钟进行计数(stm32主频72Mhz,如果对72MHz计72000个数,那就是1ms的时间),并在计数器的数值达到设定值时触发中断

components of TIM: 时基单位

16位计数器(CNT-Counter) - 每来一个时钟,计数器+1 ————0~65535

预分频器(PSC-Prescaler) - 对计数器时钟进行分频,flexible

*自动重装寄存器(ARR-AutoReloadRigister) - 计数的目标值

under72MHz下实现最大59.95s的计时 ———— = 72MHz / 65536 / 65536

TIM计算公式:

  1. 计数器CNT计数频率:CK_CNT=CK_PSC/(PSC+1) % 计算单位计时时间
  2. 计数器溢出频率:CK_CNT_OV = CK_PSC / (PSC+1) / (ARR+1) % 计算定时时间
void my_TIM_Init()
{
	/* RCC */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	// 开启TIM2时钟
    
    /* TIM2 */
    TIM_InternalClockConfig(TIM2);      // TIM2使用内部时钟
    
    // 时基单元初始化
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    // By CK_CNT_OV = CK_PSC / (PSC+1) / (ARR+1)
    TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;      // ARR 自动重装寄存器
    TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;    // RSC分频 -> 10kHz
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;   // 高级TIM才用
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
    
    // 清除更新中断位 -> 不然TIM更新事件结束就会进入中断
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    // 使能TIM_IT -> NVIC
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    /* NVIC */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     
    NVIC_InitTypeDef NVIC_InitStruct;					// 优先级分组
    NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;		// 选择TIM2中断请求通道
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;

    NVIC_Init(&NVIC_InitStruct);
    
    /* 使能TIM2 */
    TIM_Cmd(TIM2, ENABLE);
}

TIM OC

OC(Output Compare)输出比较 -> 一般用于输出PWM波

输出比较可以通过比较CNT与CCR寄存器(Compare Capture Rigister)值得关系,来对输出电平进行置1、置0或者翻转得操作,用于输出有点频率和占空比得PWM波型

每个高级定时器和通用定时器都拥有4个输出比较通道

高级定时器得前3个通道额外拥有死去生成和互补输出得功能

void my_PWM_Init()
{
	    /* ¿ªÆôRCCʱÖÓ */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    // 开启TIM2时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // 开启GPIOA时钟
    
    // TIM-OC重映射 
    //    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    //    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
    //    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    
    /* GPIO */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;            // 复用推挽输出,片上外设-》输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    /* TIM2 */
    TIM_InternalClockConfig(TIM2);      // TIM2使用内部时钟
    
    // 时基单元初始化
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    // By CK_CNT_OV = CK_PSC / (PSC+1) / (ARR+1)
    TIM_TimeBaseInitStruct.TIM_Period = 720- 1;      // ARR 自动重装寄存器
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;    // RSC分频 
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;   // 高级TIM才用
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
    
    // 清除更新中断位 -> 不然TIM更新事件结束就会进入中断
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    // 使能TIM_IT -> NVIC
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    /* TIM OC */
    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCStructInit(&TIM_OCInitStruct);                    // 结构体参数中部分参数不使用,为结构体赋初始值
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;          // 输出模式为PWM1
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;  // HIGH极性不翻转,ref直接输出
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;  // output ENA
    TIM_OCInitStruct.TIM_Pulse = 50;                        // set CCR-> dutyCycle = CCR/(ARR+1)
    
    TIM_OC1Init(TIM2, &TIM_OCInitStruct);
    
    /* ¿ªÆôTIM2ʱÖÓ */
    TIM_Cmd(TIM2, ENABLE);
}

TIM IC

对于同一个定时器,因为引脚共用OC功能与IC功能同时只能启用一个

输入捕获模式下,当通道输入引脚出现指定电平跳变,当前CNT的值将被锁存到CCR中:

—>可用于测量PWM波型的Freq,Duty,脉冲间隔,电平持续时间等参数

每个高级定时器和通用定时器都拥有4个输入捕获通道

可配置为PWMI模式,同时测量Freq和duty(两通道同时捕获一个引脚)

可配合主从触发模式,实现硬件全自动测量

TIPS:这俩配合起来,可以实现硬件全自动测量PWM

主从触发模式:

  1. 主模式(Master Mode):可以将定时器内部的信号,映射到TRGO引脚。用于触发其他外设
  2. 从模式(Slave Mode):用于接受其他外设或者自身外设的一些信号,用于控制自身定时器的运行,从模式可以在从模式列表中,选择一项操作自动执行。即被别的信号触发
  3. 触发源选择(Trigger Selection):用于选择从模式的触发信号源,选择指定的一个信号,得到TRGI,TRGI去触发从模式。
    可以实现对输入PWM波的硬件端自动测量
void my_IC_Init(void)
{
    /* RCC */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    /* GPIO */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    /* TIM */
    TIM_InternalClockConfig(TIM3);      
    // Init
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    // By CK_CNT_OV = CK_PSC / (PSC+1) / (ARR+1)
    TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;      // ARR - allow full CNT range (affect Lowest Bound)
    TIM_TimeBaseInitStruct.TIM_Prescaler = (FSYS / FMeasure)- 1;      // PSC - f_c = 1MHz
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;   
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
    
    /* TIM_IC */
    TIM_ICInitTypeDef TIM_ICInitStruct;
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStruct.TIM_ICFilter = 0xF;
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;    // Config data Selector
    TIM_ICInit(TIM3, &TIM_ICInitStruct);
    
    /* Master-Slave Config*/
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);        // Set TRGI
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);     // Choose slave mode
    
    TIM_Cmd(TIM3, ENABLE);
}

void PWMI_Init(void)
{
    /* RCC */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    /* GPIO */
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    /* TIM */
    TIM_InternalClockConfig(TIM3);      
    // Init
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    // By CK_CNT_OV = CK_PSC / (PSC+1) / (ARR+1)
    TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;      // ARR - allow full CNT range (affect Lowest Bound)
    TIM_TimeBaseInitStruct.TIM_Prescaler = (FSYS / FMeasure)- 1;      // PSC - f_c = 1MHz
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;   
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
    
    /* TIM_IC */
    TIM_ICInitTypeDef TIM_ICInitStruct;
    TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStruct.TIM_ICFilter = 0xF;
    TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;    // Config data Selector
    // Config another channel
    TIM_PWMIConfig(TIM3, &TIM_ICInitStruct);
    
    /* Master-Slave Config*/
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);        // Set TRGI
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);     // Choose slave mode
    
    TIM_Cmd(TIM3, ENABLE);
}

ADC

ADC(Analog-Digital Converter)模拟-数字转换器

ADC可以讲引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。

12位逐次逼近型ADC,1us转换时间(1MHz)

输入电压范围:03.3V,转换结果范围:04095

18个输入通道,可测量16个外部和2个内部信号源

规则组和注入组两个转换单元

模拟看门狗自动检测输入电压范围

逐次逼近型ADC

以典型ADC芯片ADC0809为例

请添加图片描述

通过比较器、DAC、逐次逼近寄存器SAR

原理是从高位到低位逐位比较,首先将缓冲寄存器各位清零;转换开始后,先将寄存器最高位置1,把值送入D/A转换器,经D/A转换后的模拟量送入比较器,称为 Vo,与比较器的待转换的模拟量Vi比较,若Vo<Vi,该位被保留,否则被清0。然后,再置寄存器次高位为1,将寄存器中新的数字量送D/A转换器,输出的 Vo再与Vi比较,若Vo<Vi,该位被保留,否则被清0。循环此过程,直到寄存器最低位,得到数字量的输出。

void my_AD_Init(void)
{
    /* RCC */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);    // Config ADC
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                       // Config ADCCLK(only 6 or 8)
    
    /* GPIO */
    GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;              // Analog IN (only for ADC)
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    /* Regular Channel */
    // channel 1 - rank 1 - Sampling time:55.5 ADC Periods
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    
    /* ADC */
    ADC_InitTypeDef ADC_InitStruct;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;    // ext_trg_src_for_regular_channels_conversion -> use software trigger
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;        // Continuous or Single mode -> Single
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;              //Scan (multichannels) or Single (one channel) mode -> Single (one channel)
    ADC_InitStruct.ADC_NbrOfChannel = 1;                    // number of ADC channels(if Single mode lose effect)
    
    ADC_Init(ADC1, &ADC_InitStruct);    //
    
    //if need
    /* IT | AWD */
    
    ADC_Cmd(ADC1, ENABLE);
    
    /* Calibration-У׼ */
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1) == SET);      // Wait till done calibration registers RESET
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1) == SET);           // Wait till done calibration
}
  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值