STM32C8T6 输入比较 输入捕获 PWM 编码器

输入比较简介:

OC Output Compare )输出比较
输出比较可以通过比较 CNT CCR 寄存器值的关系,来对输出电平进行置 1 、置 0 或翻转的操作,用于输出一定频率和占空比的 PWM 波形
每个高级定时器和通用定时器都拥有 4 个输出比较通道
高级定时器的前 3 个通道额外拥有死区生成和互补输出的功能

输入比较通道(高级):

输入比较通道(通用):

输入比较模式:

模式

描述

冻结

CNT=CCR时,REF保持为原状态

匹配时置有效电平

CNT=CCR时,REF置有效电平

匹配时置无效电平

CNT=CCR时,REF置无效电平

匹配时电平翻转

CNT=CCR时,REF电平翻转

强制为无效电平

CNTCCR无效,REF强制为无效电平

强制为有效电平

CNTCCR无效,REF强制为有效电平

PWM模式1

向上计数:CNT<CCR时,REF置有效电平,CNTCCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNTCCR时,REF置有效电平

PWM模式2

向上计数:CNT<CCR时,REF置无效电平,CNTCCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNTCCR时,REF置无效电平

PWM简介:

PWM Pulse Width Modulation )脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM 参数:

     频率 = 1 / TS            占空比 = TON / TS           分辨率 = 占空比变化步距

PWM基本结构:

参数计算:

PWM 频率:   Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM 占空比:   Duty = CCR / (ARR + 1)
PWM 分辨率:   Reso = 1 / (ARR + 1)
(PSC:预分频器        ARR:自动重装器        CNT:计数器        CRR:捕获比较器)

捕获输入简介:

IC Input Capture )输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前 CNT 的值将被锁存到 CCR 中,可用于测量 PWM 波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有 4 个输入捕获通道
可配置为 PWMI 模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量

频率测量方法:

测频法:在闸门时间 T 内,对上升沿计次,得到 N ,则频率

𝑓𝑥=𝑁 / 𝑇f_x=N / T

测周法:两个上升沿内,以标准频率 f c 计次,得到 N ,则频率

𝑓𝑥=𝑓𝑐 / 𝑁f_x=f_c  / N

中界频率:测频法与测周法误差相等的频率点

𝑓𝑚=𝑓𝑐 / 𝑇f_m=√(f_c  / T)

输入捕获通道:

主从触发模式:

输入捕获基本模式:

PWMI基本结构:

编码器接口简介:

Encoder Interface 编码器接口
编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制 CNT 自增或自减,从而指示编码器的位置、旋转方向和旋转速度
每个高级定时器和通用定时器都拥有 1 个编码器接口
两个输入引脚借用了输入捕获的通道 1 和通道 2

正交编码器:

编码器接口基本结构:

定时器代码:

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			
    //开启时钟 定时器连接APB1总线
	
	TIM_InternalClockConfig(TIM2);									//开启时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		
    //选择内部时钟分频	(1分频即为不分频)

	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
    //选择时钟计数方式	(up为向上计数)

	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				
    //周期,ARR自动重装值

	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				
    //预分频值 对72M进行7200分频,得到10khz频率

	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//基本定时器初始化
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);							//清除标志位
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);						//开启更新中断到NVIC
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);					//选择NVIC优先级
	
	NVIC_InitTypeDef NVIC_InitStructure;							//定义NVIC结构体
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;					//选择通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//NVIC使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;		//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;				//响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);											//时钟使能
}


//void TIM2_IRQHandler(void)										//定时器2的中断函数
//{
//	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)				//检查标志位
//	{
//		
//		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);					//清除标志位
//	}
//}

STM32C8T6默认频率为72M,使用定时器时,可以通过改变周期和预分频值来决定定时器。注意设定值不能超过0~65535这个区间。

定时器外部时钟:

TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);

//通过ETR引脚的外部时钟模式2配置(定时器,外部触发预分频器,外部触发极性 “NonInverted 不反向”,滤波器 0x00~0x0F)

PWM代码:

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);								    //初始化时基单元
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义输出比较结构体
	TIM_OCStructInit(&TIM_OCInitStructure);							//给结构体赋初始值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//选择PWM1模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		
    //选择输出比较极性,高极性,极性不翻转,有效电平为高电平
	
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//设置CCR寄存器的值
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)								//更改CCR的值
{
	TIM_SetCompare1(TIM2, Compare);
}

输入捕获代码:

#include "stm32f10x.h"                  // Device header

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;		//定义结构体
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;		//选择捕获通道
	TIM_ICInitStructure.TIM_ICFilter = 0xF;		//滤波器
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//选择触发极性 上升沿
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;		//选择预分频 DIV1不分频
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;		//选择触发信号从哪个引脚输入 直连通道
	TIM_ICInit(TIM3, &TIM_ICInitStructure);		//初始化输入捕获
	
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);		//触发源选择
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);		//配置从模式为Reset
	
	TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)			//返回最新周期的频率值
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

如果需要两个通道同时捕获一个引脚,可以在初始化输入捕获之类换成:

TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

这样第二个通道的参数就会被设置成与第一个通道完全相反的参数。

编码器(使用硬件,节省软件资源):

#include "stm32f10x.h"                  // Device header

void Encoder_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
		
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	//(选择定时器,选择编码器模式,选择IC极性)
	
	TIM_Cmd(TIM3, ENABLE);
}

int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3, 0);
	return Temp;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
STM32C8T6是一款STM32系列的微控制器,它支持输入捕获模式。输入捕获模式是一种用于测量外部信号的模式,可以用来测算电机的实时转速。在STM32C8T6上配置输入捕获模式的步骤如下: 1. 使能定时器和通道对应的时钟:使用RCC_APB1PeriphClockCmd()函数来使能定时器和GPIO端口的时钟。 2. 初始化IO口:使用GPIO_Init()函数来初始化用于输入捕获的GPIO端口。 3. 初始化定时器:使用TIM_TimeBaseInit()函数来初始化定时器的基本参数,如时钟分频、计数模式等。 4. 配置编码器模式:使用TIM_EncoderInterfaceConfig()函数来配置定时器的编码器模式,以支持输入捕获。 5. 初始化输入捕获通道:使用TIM_ICInit()函数来初始化输入捕获通道的参数,如捕获模式、极性等。 6. 开启更新中断:使用TIM_ITConfig()函数来开启定时器的更新中断,以便在捕获到信号时触发中断。 7. 使能定时器:使用TIM_Cmd()函数来使能定时器,开始计数。 通过以上步骤配置输入捕获模式后,每当捕获到一个信号时,定时器的CNT计数器的值会相应地加/减1。可以通过定时器中断或定时器更新事件来提取并清空计数器的值,从而计算出电机的实时转速。 #### 引用[.reference_title] - *1* *2* *3* [【STM32STM32F103C8T6使用外部中断法和输入捕获法进行编码器测速](https://blog.csdn.net/qq_52785580/article/details/122984096)[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^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值