stm32 TIM定时器 PWM脉冲输出[操作寄存器+库函数]

发布者:清新天空最新更新时间:2017-02-06 来源: eefocus关键字:stm32  TIM定时器  PWM  脉冲输出 手机看文章 扫描二维码
随时随地手机看文章

脉冲调制(PWM)是利用微处理器对数字输出来对模拟电路的一种非常有效的技术。简单点说就是对确定频率的信号,调整其占空比。

 

stm32的定时器除了TIM6和TIM7外,其他定时器都可以产生PWM输出。其中高级定时器TIM1和TIM8可以产生多达7路的PWM输出。通用定时器可以产生4路的PWM输出。

 

stm32 TIM定时器[操作寄存器+库函数]  中我们是通过在中断中,翻转指定引脚的电平。在stm32中可以通过配置一个捕获/比较模式寄存器(TIMx_CCMR),设置通道引脚输出模式为PWM脉冲模式,在计时器计数到捕获/比较模式寄存器的值,指定引脚会输出一个有效电平,这样就可以通过定时器直接产生 PWM脉冲。这种方式下不需要开启中断。

 

  • 这里说有效电平是因为这个电平不一定为1,这个在 捕获/比较使能寄存器(TIMx_CCER)中可以设置有效电平的极性。

  • 指定引脚不是任意的,这个stm32对每个定时器通道有特定的引脚对应 对应关系如下

 

TIMx_CHx 对应的I/O口就是此通道对应的引脚

 

IMG_20120417_143213.jpg

 

可以看出 TIM2的 OC通道 1-4 对应的就是   GPIOA 0-3 

 

此例直接操作寄存器实现 Led灯由暗到亮再由亮到暗的呼吸灯效果。库函数实现用PWM脉冲输出模式,产生4个不同频率的脉冲,让led闪烁。


 

直接操作寄存器

 

通用定时器的每个通道都有6种输出模式,其中有两种PWM模式。通过捕获/比较模式寄存器1(TIMx_CCMR1)设定,由OC1M[2:0]三位决定。6种模式如下:

  • 000:冻结。输出比较寄存器TIMx_CCR1与计数器TIMx_CNT间的比较对OC1REF不起作用;

  • 001:匹配时设置通道1为有效电平。当计数器TIMx_CNT的值与捕获/比较寄存器1 (TIMx_CCR1)相同时,强制OC1REF为高。

  • 010:匹配时设置通道1为无效电平。当计数器TIMx_CNT的值与捕获/比较寄存器1 (TIMx_CCR1)相同时,强制OC1REF为低。

  • 011:翻转。当TIMx_CCR1=TIMx_CNT时,翻转OC1REF的电平。

  • 100:强制为无效电平。强制OC1REF为低。

  • 101:强制为有效电平。强制OC1REF为高。

  • 110:PWM模式1- 在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。

  • 111:PWM模式2- 在向上计数时,一旦TIMx_CNTTIMx_CCR1时通道1为有效电平,否则为无效电平。 

两种PWM模式,区别在于通道的电平极性是相反的。

 

首先需要设定TIMx_CCMR1寄存器:  

TIMx_CCMR1.png

 

OCxM[2:0]已经做了介绍,OC2CE:输出比较2清0使能  OC2PE:输出比较2预装载使能 

通过设定OC2M[2:0]为 110/111 为PWM脉冲输出模式。

 

设定TIMx_CCER寄存器相关位,使能通道输出,还可以设置有效电平极性。

 

最后一个就是调整占空比的关键寄存器,捕获/比较寄存器(TIMx_CCRx),低16位有效,这个寄存器已经使用过,要实现PWM脉冲的占空比可调的原理就是不断改变这个寄存器的值。

 

要实现led亮暗的渐变,PWM的频率不能太低,低于50Hz的时候就会明显感觉到闪烁。这里用8khz的频率,调整PWM输出占空比,从0到不断增大其占空比,再递减为0.

 

代码如下: (system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置

User/main.c

#include 	 
#include "system.h" 
#include "tim.h" 	

void Gpio_Init(void);

int main(void)
{				  
	u32 var=0,flag=0;

	Rcc_Init(9); 			 //系统时钟设置

	// 相关TIM_x,CCR_x参数定义tim.h文件

	Tim_Init(TIM_3,900,0);  //初始化TIM3定时器,设定重装值和分频值

	Tim_OC_Set(TIM_3,OC_2,7);    //设定TIM3 通道1为PWM输出模式

	Gpio_Init();

	while(1){		

		delay(5000);	  //延时5ms

		if(flag){
			var--;
		}else{
			var++;
		}

		if(var>300) flag = 1; 
		
		if(var == 0) flag = 0;

		Tim_CCR_Set(TIM_3,OC_2,var); 	
	}

}


void Gpio_Init(void)
{
	RCC->APB2ENR|=1<<2;    //使能PORTA时钟 	   	 

	  	
	GPIOA->CRL&=0X0FFFFFFF;//PA7输出
	GPIOA->CRL|=0XB0000000;//复用功能输出 	  
  
}

 

Library/src/tm.c

#include 	 
#include "tim.h" 


//通用定时器初始化
//参数说明:TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h), arr为自动重装值 ;psc 为时钟预分频数
//要使用定时器的其他函数,必须先调用此函数,因为时钟在这个函数中开启
//TIM3用于PWM输出已测试
//待完善 目前只支持TIM2	
//其他定时器只做了开启时钟处理
void Tim_Init(u8 TIM_x,u16 arr,u16 psc)
{
	switch(TIM_x)
	{
	 	case 1 :{  RCC->APB2ENR |=1<<11; break;  }	     //TIM1高级定时器设置
		case 2 :{										 //TIM2通用定时器设置

			RCC->APB1ENR |=1<<0;

			TIM2->ARR = arr;			//设定自动重装值
			TIM2->PSC = psc;		    //设定预分频值
			TIM2->DIER |= 1<<0;			//允许更新中断
			TIM2->DIER |= 1<<6;			//允许触发中断

 			TIM2->CR1 |= 0x81;			//使能定时器,自动重装允许 	
								
			break;
		}

		case 3 :{

			RCC->APB1ENR |=1<<1;

			TIM3->ARR = arr;			//设定自动重装值
			TIM3->PSC = psc;		    //设定预分频值
			//TIM3->DIER |= 1<<0;			//允许更新中断
			//TIM3->DIER |= 1<<6;			//允许触发中断
			TIM3->CR1 |= 0x81;			//使能定时器			

			break;
		}
		case 4 :{
			RCC->APB1ENR |=1<<2;

			TIM4->ARR = arr;			//设定自动重装值
			TIM4->PSC = psc;		    //设定预分频值
			TIM4->DIER |= 1<<0;			//允许更新中断
			TIM4->DIER |= 1<<6;			//允许触发中断
			TIM4->CR1 |= 0x01;			//使能定时器 						

			break;
		}

		case 5 :{
			RCC->APB1ENR |=1<<3;

			TIM5->ARR = arr;			//设定自动重装值
			TIM5->PSC = psc;		    //设定预分频值
			TIM5->DIER |= 1<<0;			//允许更新中断
			TIM5->DIER |= 1<<6;			//允许触发中断
			TIM5->CR1  |= 0x01;			//使能定时器			

			break;
		}
	 	case 6 :{  RCC->APB1ENR |=1<<4;   break;  }		
	 	case 7 :{  RCC->APB1ENR |=1<<5;   break;  }
	 	case 8 :{  RCC->APB2ENR |=1<<13;  break;  }

	}
}



//捕获比较值设定函数
//参数说明:
//			TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h)
//			OC_x 为选择通道,以确定捕获/比较寄存器(1~4)(定义于tim.h)
//			val   为要设定的捕获/比较寄存器的值
// TIM3,OC_2 用于PWM输出已测试
// 待完善,目前只支持TIM2

void Tim_CCR_Set(u8 TIM_x,u8 OC_x,u32 val)
{
	switch(TIM_x)
	{
	 	case 1 :{ break;}
		case 2 :{

			TIM2->DIER |= 1 << OC_x;			//开启相应允许捕获/比较中断

			switch(OC_x){

				case 1: {
					TIM2 ->CCR1 = val;		 //设置捕获/比较1的值 
					break;
				}

				case 2: {
					TIM2 ->CCR2 = val;		 //设置捕获/比较2的值 
					break;
				}

				case 3: {
					TIM2 ->CCR3 = val;		 //设置捕获/比较3的值 
					break;
				}

				case 4: {
					TIM2 ->CCR4 = val;		 //设置捕获/比较4的值 
					break;
				}
			}
					
			break;
		}

		case 3 :{
			//TIM3->DIER |= 1 << OC_x;			//开启相应允许捕获/比较中断

			switch(OC_x){

				case 1: {
					TIM3 ->CCR1 = val;		 //设置捕获/比较1的值 
					break;
				}

				case 2: {
					TIM3 ->CCR2 = val;		 //设置捕获/比较2的值 
					break;
				}

				case 3: {
					TIM3 ->CCR3 = val;		 //设置捕获/比较3的值 
					break;
				}

				case 4: {
					TIM3 ->CCR4 = val;		 //设置捕获/比较4的值 
					break;
				}
			}			

			break;
		}
		case 4 :{ break;}
		case 5 :{ break;}
	 	case 6 :{ break;}
	 	case 7 :{ break;}
	 	case 8 :{ break;}

	}
}

//定时器通道引脚输出模式设定函数
//参数说明:
//			TIM_x 为选择定时器 TIM_1为通用寄存器1又一次类推(定义于tim.h)
//			OC_x  为选择输出通道选择(1~4)(定义于tim.h)
//			Mode   为选择通道对应引脚输出模式(0~7)
// TIM3,OC_2 用于PWM输出已测试
// 待完善,目前只支持TIM2

void Tim_OC_Set(u8 TIM_x,u8 OC_x,u8 Mode)		  
{
	switch(TIM_x)	
	{
	 	case 1 :{ break;}

		case 2 :{

			switch(OC_x){

				case 1: {
					TIM2 ->CCMR1 |= Mode <<4;     //设定引脚输出模式
					TIM2 ->CCMR1 |= 1<<3;		 //允许预装载

					//TIM2 ->CCER  |= 1<<2;       //引脚输出低电平为有效
					TIM2 ->CCER  |= 1<<0;		 //OC1 输出使能
					break;
				}

				case 2: {
					TIM2 ->CCMR1 |= Mode <<12;     //设定引脚输出模式
					TIM2 ->CCMR1 |= 1<<11;		 //允许预装载

					//TIM2 ->CCER  |= 1<<5;       //引脚输出低电平为有效
					TIM2 ->CCER  |= 1<<4;		 //OC2 输出使能
					break;
				}

				case 3: {
					TIM2 ->CCMR2 |= Mode <<4;     //设定引脚输出模式
					TIM2 ->CCMR2 |= 1<<3;		 //允许预装载

					//TIM2 ->CCER  |= 1<<9;       //引脚输出低电平为有效
					TIM2 ->CCER  |= 1<<8;		 //OC3 输出使能
					break;
				}

				case 4: {
					TIM2 ->CCMR2 |= Mode <<12;     //设定引脚输出模式
					TIM2 ->CCMR2 |= 1<<11;		 //允许预装载

					//TIM2 ->CCER |= 1<<5;       //引脚输出低电平为有效
					TIM2 ->CCER  |= 1<<4;		 //OC1 输出使能
					break;
				}
			}
					
			break;
		}

		case 3 :{

			switch(OC_x){

				case 1: {
					TIM3 ->CCMR1 |= Mode <<4;     //设定引脚输出模式
					TIM3 ->CCMR1 |= 1<<3;		 //允许预装载

					//TIM3 ->CCER  |= 1<<2;       //引脚输出低电平为有效
					TIM3 ->CCER  |= 1<<0;		 //OC1 输出使能
					break;
				}

				case 2: {
					TIM3 ->CCMR1 |= Mode <<12;     //设定引脚输出模式
					TIM3 ->CCMR1 |= 1<<11;		 //允许预装载

					TIM3 ->CCER  |= 1<<5;       //引脚输出低电平为有效
					TIM3 ->CCER  |= 1<<4;		 //OC2 输出使能
					break;
				}

				case 3: {
					TIM3 ->CCMR2 |= Mode <<4;     //设定引脚输出模式
					TIM3 ->CCMR2 |= 1<<3;		 //允许预装载

					//TIM3 ->CCER  |= 1<<9;       //引脚输出低电平为有效
					TIM3 ->CCER  |= 1<<8;		 //OC3 输出使能
					break;
				}

				case 4: {
					TIM3 ->CCMR2 |= Mode <<12;     //设定引脚输出模式
					TIM3 ->CCMR2 |= 1<<11;		 //允许预装载

					//TIM3 ->CCER  |= 1<<5;       //引脚输出低电平为有效
					TIM3 ->CCER  |= 1<<4;		 //OC1 输出使能
					break;
				}
			}
					
			break;
		}
		case 4 :{ break;}
		case 5 :{ break;}
	 	case 6 :{ break;}	
	 	case 7 :{ break;}
	 	case 8 :{ break;}
	}
}

Library/inc/tim.h

#include 

#define  TIM_1  0x01
#define  TIM_2  0x02
#define  TIM_3  0x03
#define  TIM_4  0x04
#define  TIM_5  0x05
#define  TIM_6  0x06
#define  TIM_7  0x07
#define  TIM_8  0x08

#define  OC_1  0x01
#define  OC_2  0x02
#define  OC_3  0x03
#define  OC_4  0x04


void Tim_Init(u8 TIM_x,u16 arr,u16 psc); 
void Tim_CCR_Set(u8 TIM_x,u8 OC_x,u32 val);
void Tim_OC_Set(u8 TIM_x,u8 OC_x,u8 Mode);

这里还需要注意的是 Led的连接方式,我的led是低电平亮的 ,如果你的Led是高电平点亮,可以设置通道引脚输出极性为高电平有效。 在Tim_OC_Set()函数中可以设置 ,此例中选用TIM3的OC2通道,只需要注释 TIM3 ->CCER  |= 1<<5;       //引脚输出低电平为有效 这句代码即可。

 

库函数操作

 

要输出PWM脉冲 必须要 将io 设置为复用推挽    

     

代码如下: main.c 


#include "stm32f10x.h"

vu16 CCR1_Val = 60000;
vu16 CCR2_Val = 30000;
vu16 CCR3_Val = 15000;
vu16 CCR4_Val = 7500;              

void RCC_Configuration(void);
void GPIO_Configuration(void);
void TIM_Configuration(void);

int main(void)
{
   
  	RCC_Configuration();
  	GPIO_Configuration();
	TIM_Configuration();
	while(1);
}

void TIM_Configuration(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_TimeBaseStructure.TIM_Period = 65535;
	TIM_TimeBaseStructure.TIM_Prescaler = 7199;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

	//TIM_PrescalerConfig(TIM2,7199,TIM_PSCReloadMode_Immediate);

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	 //使能TIM输出
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
 	TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
	TIM_OC4Init(TIM2,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);
	TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);
	TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);

	//TIM_ITConfig(TIM2,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);
	
	TIM_Cmd(TIM2,ENABLE);

}


  
void GPIO_Configuration(void)
{
  	GPIO_InitTypeDef GPIO_InitStructure;

  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;			//设置为复用推挽
  	GPIO_Init(GPIOA , &GPIO_InitStructure); 
}


void RCC_Configuration(void)
{
	/* 定义枚举类型变量 HSEStartUpStatus */
	ErrorStatus HSEStartUpStatus;

  	/* 复位系统时钟设置*/
  	RCC_DeInit();
  	/* 开启HSE*/
  	RCC_HSEConfig(RCC_HSE_ON);
  	/* 等待HSE起振并稳定*/
  	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	/* 判断HSE起是否振成功,是则进入if()内部 */
  	if(HSEStartUpStatus == SUCCESS)
  	{
    	/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
    	RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    	/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
    	RCC_PCLK2Config(RCC_HCLK_Div1); 
    	/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
    	RCC_PCLK1Config(RCC_HCLK_Div2);
    	/* 设置FLASH延时周期数为2 */
    	FLASH_SetLatency(FLASH_Latency_2);
    	/* 使能FLASH预取缓存 */
    	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    	/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
    	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    	/* 使能PLL */ 
    	RCC_PLLCmd(ENABLE);
    	/* 等待PLL输出稳定 */
    	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    	/* 选择SYSCLK时钟源为PLL */
    	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    	/* 等待PLL成为SYSCLK时钟源 */
    	while(RCC_GetSYSCLKSource() != 0x08);
  	} 
  	/* 打开APB2总线上的GPIOA时钟*/
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
	
}


关键字:stm32  TIM定时器  PWM  脉冲输出 引用地址:stm32 TIM定时器 PWM脉冲输出[操作寄存器+库函数]

上一篇:stm32 TIM定时器[操作寄存器+库函数]
下一篇:stm32 窗口看门狗[操作寄存器+库函数]

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

stm32笔记:点亮一个led (精简版)
仅包含启动文件 STM32F10x.s C代码 #define GPIOA_CRL (*(volatile unsigned long *)(0x40000000+0x10000+0x0800+0x00)) #define GPIOA_CRH (*(volatile unsigned long *)(0x40000000+0x10000+0x0800+0x04)) #define GPIOA_IDR (*(volatile unsigned long *)(0x40000000+0x10000+0x0800+0x08)) #define GPIOA_ODR (*(volatile unsigned
[单片机]
<font color='red'>stm32</font>笔记:点亮一个led (精简版)
GPIO的描述和配置
首先介绍stm32的GPIO,这是入门的起点,也是最容易上手的部分。 一、GPIO的综合描述 stm32每一个GPIO端口拥有2个32bits的configuration寄存器(GPIOx_CRL,GPIOx_CRH),2个32bits的数据寄存器(GPIOx_IDR,GPIOx_ODR),1个32bits的set/reset寄存器(GPIOx_BSRR),1个16bits的reset寄存器(GPIOx_BRR)和1个32bits的Lock寄存器(GPIOx_LCKR)。 (一)每一个IO引脚都可以使用软件配置为以下几种模式: 1. 浮空输入 2. 带上拉输入 3. 带下拉输入 4. 模拟输入 5. 开漏输出——
[单片机]
STM32独立看门狗(宠物狗)
一、前言 ······在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) ,其主要功能是:能够让CPU复位的一个硬件。 ······看门狗( watchdog timer),是一个定时器电路, 一般有一个输入,叫喂狗(kicking the dog or service the dog),一个输出到MCU的RST端,MCU正常工作
[单片机]
<font color='red'>STM32</font>独立看门狗(宠物狗)
STM32存储器地址映射
上图是STM32的存储器地址映射图,地址范围为:0x0000_0000-0xFFFF_FFFF;其中代码区的地址是从0x0800_0000开始的,结束于0x0800_0000+芯片的Flash的大小,RAM的起始地址是0x2000_0000,结束于0x2000_0000+芯片的RAM大小。 支持位带操作的两个内存区的范围是: 0x2000_0000‐0x200F_FFFF( SRAM 区中的最低 1MB) 0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB) 其中对于SRAM位带区的某个比特位,假设它的地址为Addr,位序号为n(0 =n =7),则该比特在别名区的地址为: Bit_Addr=0x2200
[单片机]
STM32学习记录——printf函数重定位
功能: 重定位printf函数,使printf作为串口打印输出函数。代替usart_send_string()函数 步骤: usart.c中包含USART初始化函数 1、USART初始化(使能时钟、使能GPIO、GPIO和USART初始化) 2、打开USART 3、在usart.c中加入如下代码 #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker- Libraries- Small printf set to 'Yes') calls __io_putchar() */ #define PUT
[单片机]
PWM变频器及应用技术研究
  1 引言   通用型变频器, 由于其整流环节不可控, 存在网侧功率因数低、电流谐波大、能量不可逆的缺点。双PWM变频器是在一般通用变频器的基础上引进了PWM 整流的能量变换装置。该装置能够提高电能的利用率, 把由电动机产生的再生能源回馈到交流电网, 并且能提高装置的功率因数, 能主动地消除变频装置对电网的谐波污染。由于PWM 整流,变频器中间直流环节的电压能保持稳定, 通过整流桥和逆变桥的功率平衡控制, 能大大减小直流电容的容量, 提高了变频器的调速性能且节能效果显着。   文中对四象限变频器进行数学建模, 然后在其基础上提出了有功功率和无功功率解耦控制的策略, 并网电压定向使用了软件锁相环的方法, 提高了锁相速度,
[电源管理]
双<font color='red'>PWM</font>变频器及应用技术研究
关于STM32中CAN中断的使用
如果你用的CAN引脚是PA11和PA12,接收中断用CAN1_RX0_IRQn。如果CAN引脚用的是PB8和PB9,也就是用重定义的引脚,接收中断用CAN1_RX1_IRQn。由于PA11和PA12也是USB的引脚,所以非互联型且带CAN控制器的微控制器的库文件在起名字时用了USB_LP_CAN1_RX0_IRQn。 具体的定义可以参考stm32F10x.h文件,其中对不同型号的中断有具体的定义。 示例如下: 1. 配置过滤器 CAN_FilterInitStructure.CAN_FilterNumber = 0; CAN_FilterInitStructure.CAN_FilterMode = CAN_F
[单片机]
STM32的硬件I2C设计有BUG
坊间一直流传着一个传说~STM32的硬件I2C设计有BUG,最好不要用,用软件I2C比较靠谱。长久以来,为了不必要的麻烦,我也一直没有用过硬件I2C,主要是软件I2C也比较方便,基本上任意端口都可以用。 最近画了块板子,正好用到了I2C,就顺便来测试一下硬件I2C是不是真的像有些人说的不好用。 测试硬件:STM32F407VET6+AT24C64测试软件:STM32CubeMX v6.1.1HAL库:STM32CubeF4 Firmware Package V1.25.2 STM32CubeMX配置 使用STM32CubeMX配置很方便,时钟等基础配置不再详细介绍,直接看I2C配置如下: 这里的速度模式选择为标准模式,
[单片机]
<font color='red'>STM32</font>的硬件I2C设计有BUG
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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