stm32-led-串口-PWM

因为项目需要,学习了一下stm32的GPIO,串口,PWM,中断部分,在这里做个小结, 共同学习,所有程序均经过实际测试,输出正确。

将GPIO,串口,PWM(定时器)的配置程序粘贴如下

1、使能外设的时钟:APB1ENR,APB2ENR

2、配置寄存器或者说是控制寄存器。在配置stm32外设时,任何时候都要先使能该外设的时钟!而每个控制寄存器,很有可能包括了,1模式寄存器,2使能寄存器,3才可能是我们认为的数据寄存器或者内容寄存器。

3、使能外设。即使配置好了,没有使能外设,则外设永远不会工作,这一点比较容易遗忘。

 

寄存器配置,请查看

http://wenku.baidu.com/link?url=NE4LMJFepztwPxYEb0n72SMNZLTruz32JsEJNPAtcV9AcS9OpA6CoLrJGllXzW5relKtY2c8MBKWURnBdYZG_sNj7yg_JFo7cpdut4k1mzS

 

由于stm32的很多引脚都是复用,所以在配置寄存器配置时,必须设置为复用,复用切记是默认的复用功能为主,参考文档,请查看

http://download.csdn.net/detail/bolvtin/8867933

 

1、外设时钟寄存器

RCC_APB1ENR(APB1外设时钟使能寄存器)

RCC_APB2ENR(APB2外设时钟使能寄存器)

 

RCC_APB2RSTR(APB2外设复位寄存器)

RCC_APB1RSTR(APB1外设复位寄存器)

 

外设使能寄存器与外设复位寄存器存在着对应关系,相应位置对应相应外设的时钟使能与复位。

 

注意以下几个外设

1,GPIO--GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF,GPIOG时钟都在RCC_APB2ENR寄存器

2,串口--USART1时钟都在RCC_APB2ENR寄存器

3,定时器—TIM1,TIM8时钟都在RCC_APB2ENR寄存器

 

1,串口—USART2,USART3,USART4,USART5时钟都在RCC_APB1ENR寄存器

2,定时器—TIM2,TIM3,TIM4,TIM5,TIM6,TIM7时钟都在RCC_APB1ENR寄存器,TIM2- TIM5可以产生PWM

 

   注意一下定时器的内部时钟信号来源

   当APB1的时钟分频数设置为1,通用定时器的时钟就是APB1的时钟;当APB1的时钟分频数设置为2,通用定时器TIMx的时钟是APB1的2倍,即72Mhz。高级定时器1,8的时钟来自于APB2,不是APB1。


程序部分:

led.h

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"
//Mini STM32开发板
//LED驱动代码			 
//正点原子@ALIENTEK
//2010/5/27

//LED端口定义
#define LED0 PAout(8)// PA8
#define LED1 PDout(2)// PD2	

void LED_Init(void);//初始化		 				    
#endif


led.c

#include <stm32f10x_lib.h>	   
#include "led.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//LED驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/5/27
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved											  
// 	   

//初始化PA8和PD2为输出口.并使能这两个口的时钟		    
//LED IO初始化

/********************************************************************************/
void LED_Init(void)
{
//总体是3部分
//1、使能GPIO的时钟,这里假设使能了A、B、C、D4个GPIO外设
//2、配置寄存器,是输入还是输出,是默认的定义,还是默认的复用功能
//3、填写默认的数据参数,这里选择了,默认输出高电平
	RCC->APB2ENR|=1<<2;    //使能PORTA时钟
	RCC->APB2ENR|=1<<3;    //使能PORTB时钟
	RCC->APB2ENR|=1<<4;    //使能PORTC时钟	   	 
	RCC->APB2ENR|=1<<5;    //使能PORTD时钟	
	   	 
	GPIOA->CRH&=0XFFFFFFF0;  //清掉PA8位原来的设置,同时不影响其他位的设置 在mini stm32上 PA8连接了DS0灯
	GPIOA->CRH|=0X00000003;//PA8 推挽输出   	 
    GPIOA->ODR|=1<<8;      //PA8 输出高
	
	GPIOC->CRH&=0XFFF00FFF; 
	GPIOA->CRH|=0X00038000;//PC11 输入 PC12 输出   	 
    GPIOA->ODR=1<<11;      //PC11 上拉
	GPIOA->ODR|=1<<12;      //PC.12 输出高 	

											  
	GPIOD->CRL&=0XFFFFF0FF;				  //在mini stm32上 PD2连接了DS1灯
	GPIOD->CRL|=0X00000300;//PD.2推挽输出
	GPIOD->ODR|=1<<2;      //PD.2输出高 
}

timer.h

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//通用定时器 驱动代码			   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/12/03
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
// 	  

//通过改变TIM3->CCR2的值来改变占空比,从而控制LED0的亮度
#define LED0_PWM_VAL TIM3->CCR2 

void Timerx_Init(u16 arr,u16 psc);
void PWM_Init(u16 arr,u16 psc);
#endif


usart.h

#ifndef __USART_H
#define __USART_H
#include <stm32f10x_lib.h>
#include "stdio.h"	 
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//串口1初始化		   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/5/27
//版本:V1.3
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
//********************************************************************************
//V1.3修改说明 
//支持适应不同频率下的串口波特率设置.
//加入了对printf的支持
//增加了串口接收命令功能.
//修正了printf第一个字符丢失的bug
// 	  
 
	  	
extern u8 USART_RX_BUF[64];     //接收缓冲,最大63个字节.末字节为换行符 
extern u8 USART_RX_STA;         //接收状态标记


extern char imgCenterX[5];
extern char imgCenterY[5];	

extern int imgCenterX0,imgCenterX1;
extern int imgCenterY0,imgCenterY1;

//如果想串口中断接收,请不要注释以下宏定义
#define EN_USART1_RX //使能串口1接收
#define EN_USART2_RX //使能串口2接收
#define EN_USART3_RX //使能串口3接收
void uart_init(u32 pclk2,u32 bound);

#endif	   


usart.c

#include "sys.h"
#include "usart.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//串口1初始化		   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/5/27
//版本:V1.3
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
//********************************************************************************
//V1.3修改说明 
//支持适应不同频率下的串口波特率设置.
//加入了对printf的支持
//增加了串口接收命令功能.
//修正了printf第一个字符丢失的bug
// 	  
 

//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
	/* Whatever you require here. If the only file you are using is */ 
	/* standard output using printf() for debugging, no file handling */ 
	/* is required. */ 
}; 
/* FILE is typedef’ d in stdio.h. */ 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数,因为这个串口在ministm32上定义为PA9与PA10 与USB转串口的芯片 连接 因此便于与PC机通讯,方便通过串口助手调试,所以不再重定义为其他串口输出
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
	USART1->DR = (u8) ch;      
	return ch;
}
自己的重定义fputc函数 
//我们还是定义USART1作为printf函数的重定义 输出串口,但是用USART3进行linux的串口输入 
//int fputc(int ch, FILE *f)
//{      
//	while((USART3->SR&0X40)==0);//循环发送,直到发送完毕   
//	USART3->DR = (u8) ch;      
//	return ch;
//}
#endif

//在stm32中,串口即用GPIO的复用功能输出 由下面链接可以看出,
//http://download.csdn.net/detail/bolvtin/8867933
//PA9--USART1_TX 输出 PA10--USART1_RX 输入
//PA2--USART2_TX 输出 PA3--USART2_RX  输入  
//PB10--USART3_TX 输出;PB11--USART3_RX 输入

/********************************************************************************/
//这里本来是用 串口1既不停地接收另一个PC机B的串口数据,并且在程序里再不断把数据发送给PC机A(上面有串口调试助手,以观察数据)的
//但是发现,串口1在不断接收的同时,如果不停地再往外发,数据就会丢失很多,导致程序错误,
//因此设置为,从串口3接收PC机B的数据,从串口1发送给PC机A的串口调试助手以观察数据

//#ifdef EN_USART1_RX   //如果使能了接收
串口1中断服务程序
注意,读取USARTx->SR能避免莫名其妙的错误   	
//u8 USART_RX_BUF[64];     //接收缓冲,最大64个字节.
接收状态
bit7,接收完成标志
bit6,接收到0x0d
bit5~0,接收到的有效字节数目
//u8 USART_RX_STA=0;       //接收状态标记	  
//
//char imgCenterX[5];
//char imgCenterY[5];
//
//int imgCenterX0=320,imgCenterX1;//对应的图片为宽*高=640*480的
//int imgCenterY0=240,imgCenterY1;
//
//void USART1_IRQHandler(void)
//{
//	u8 res;	    
//	if(USART1->SR&(1<<5))//接收到数据
//	{	 
//		res=USART1->DR; 
//		if((USART_RX_STA&0x80)==0)//接收未完成
//		{
//			//if(USART_RX_STA&0x40)//接收到了0x0d,把USART_RX_STA设置为0100 0000
//			if(USART_RX_STA&0x40)//接收到了$美金符号 王博
//			{
//				//if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
//				if(res!=0x24)USART_RX_STA=0;//接收错误,重新开始
//				else 
//				{
//				
//				USART_RX_STA|=0x80;	//接收完成了
//				imgCenterX[0]=USART_RX_BUF[14];		  //第15个字节
//				imgCenterX[1]=USART_RX_BUF[15];
//				imgCenterX[2]=USART_RX_BUF[16];
//				imgCenterX[3]=USART_RX_BUF[17];
//	
//				imgCenterY[0]=USART_RX_BUF[36];
//				imgCenterY[1]=USART_RX_BUF[37];
//				imgCenterY[2]=USART_RX_BUF[38];
//				imgCenterY[3]=USART_RX_BUF[39];
//
//				imgCenterX1=atoi(imgCenterX);
//				//printf("%d\n",imgCenterX1);
//
//				imgCenterY1=atoi(imgCenterY);
//				//printf("%d\n",imgCenterY1);
//			
//				}
//			}else //还没收到0X0D
//			{	
//				//if(res==0x0d)USART_RX_STA|=0x40;
//				if(res==0x24)USART_RX_STA|=0x40;
//				else
//				{
//					USART_RX_BUF[USART_RX_STA&0X3F]=res;
//					USART_RX_STA++;
//					if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收	  
//				}		 
//			}
//		}  		 									     
//	} 										 
//}
//#endif 
/********************************************************************************/
//mini stm32 串口2

#ifdef EN_USART2_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[64];     //接收缓冲,最大64个字节.
//接收状态
//bit7,接收完成标志
//bit6,接收到0x0d
//bit5~0,接收到的有效字节数目
u8 USART_RX_STA=0;       //接收状态标记	  

char imgCenterX[5];
char imgCenterY[5];

int imgCenterX0=320,imgCenterX1=320;//对应的图片为宽*高=640*480的
int imgCenterY0=240,imgCenterY1=240;

void USART2_IRQHandler(void)
{
	u8 res;	    
	if(USART2->SR&(1<<5))//接收到数据
	{	 
		res=USART2->DR; 
		if((USART_RX_STA&0x80)==0)//接收未完成
		{
			//if(USART_RX_STA&0x40)//接收到了0x0d,把USART_RX_STA设置为0100 0000
			if(USART_RX_STA&0x40)//接收到了$美金符号 tinbo
			{
				//if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				if(res!=0x24)USART_RX_STA=0;//接收错误,重新开始
				else 
				{
				
				USART_RX_STA|=0x80;	//接收完成了
				imgCenterX[0]=USART_RX_BUF[14];		  //第15个字节
				imgCenterX[1]=USART_RX_BUF[15];
				imgCenterX[2]=USART_RX_BUF[16];
				imgCenterX[3]=USART_RX_BUF[17];
	
				imgCenterY[0]=USART_RX_BUF[36];
				imgCenterY[1]=USART_RX_BUF[37];
				imgCenterY[2]=USART_RX_BUF[38];
				imgCenterY[3]=USART_RX_BUF[39];

				imgCenterX1=atoi(imgCenterX);
				//printf("%d\n",imgCenterX1);

				imgCenterY1=atoi(imgCenterY);
				//printf("%d\n",imgCenterY1);
			
				}
			}else //还没收到0X0D
			{	
				//if(res==0x0d)USART_RX_STA|=0x40;
				if(res==0x24)USART_RX_STA|=0x40;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3F]=res;
					USART_RX_STA++;
					if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}  		 									     
	}
	else
	{
		
	} 										 
} 
#endif
/********************************************************************************/
//mini stm32 串口3

//#ifdef EN_USART3_RX   //如果使能了接收
串口1中断服务程序
注意,读取USARTx->SR能避免莫名其妙的错误   	
//u8 USART_RX_BUF[64];     //接收缓冲,最大64个字节.
接收状态
bit7,接收完成标志
bit6,接收到0x0d
bit5~0,接收到的有效字节数目
//u8 USART_RX_STA=0;       //接收状态标记	  
//
//char imgCenterX[5];
//char imgCenterY[5];
//
//int imgCenterX0=320,imgCenterX1=320;//对应的图片为宽*高=640*480的
//int imgCenterY0=240,imgCenterY1=240;
//
//void USART3_IRQHandler(void)
//{
//	u8 res;	    
//	if(USART3->SR&(1<<5))//接收到数据
//	{	 
//		res=USART3->DR; 
//		if((USART_RX_STA&0x80)==0)//接收未完成
//		{
//			//if(USART_RX_STA&0x40)//接收到了0x0d,把USART_RX_STA设置为0100 0000
//			if(USART_RX_STA&0x40)//接收到了$美金符号 王博
//			{
//				//if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
//				if(res!=0x24)USART_RX_STA=0;//接收错误,重新开始
//				else 
//				{
//				
//				USART_RX_STA|=0x80;	//接收完成了
//				imgCenterX[0]=USART_RX_BUF[14];		  //第15个字节
//				imgCenterX[1]=USART_RX_BUF[15];
//				imgCenterX[2]=USART_RX_BUF[16];
//				imgCenterX[3]=USART_RX_BUF[17];
//	
//				imgCenterY[0]=USART_RX_BUF[36];
//				imgCenterY[1]=USART_RX_BUF[37];
//				imgCenterY[2]=USART_RX_BUF[38];
//				imgCenterY[3]=USART_RX_BUF[39];
//
//				imgCenterX1=atoi(imgCenterX);
//				//printf("%d\n",imgCenterX1);
//
//				imgCenterY1=atoi(imgCenterY);
//				//printf("%d\n",imgCenterY1);
//			
//				}
//			}else //还没收到0X0D
//			{	
//				//if(res==0x0d)USART_RX_STA|=0x40;
//				if(res==0x24)USART_RX_STA|=0x40;
//				else
//				{
//					USART_RX_BUF[USART_RX_STA&0X3F]=res;
//					USART_RX_STA++;
//					if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收	  
//				}		 
//			}
//		}  		 									     
//	}
//	else
//	{
//		
//	} 										 
//} 
//#endif

/********************************************************************************/										 
//初始化IO 串口
//pclk2:PCLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2,u32 bound)
{  	 
	float temp;
	u16 mantissa;
	u16 fraction;

	float temp2;
	u16 mantissa2;
	u16 fraction2;
		
	float temp3;
	u16 mantissa3;
	u16 fraction3;

//总体是3部分
//1、使能串口1时钟。但是因为用到了GPIO口,所以需要使能GPIO的时钟,这里假设使能了A、B、C、D4个GPIO外设,包括了GPIO口的3个步骤
//2、配置寄存器,配置波特率、停止位、校验位等
//3、串口使能,接收缓冲区非空中断使能

/********************************************************************************/
//串口1 的初始化	   
	temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
	mantissa=temp;				 //得到整数部分
	fraction=(temp-mantissa)*16; //得到小数部分	 
    mantissa<<=4;
	mantissa+=fraction;

	RCC->APB2ENR|=1<<2;   //使能PORTA口时钟  
	RCC->APB2ENR|=1<<14;  //使能串口1时钟 
	GPIOA->CRH&=0XFFFFF00F; 
	GPIOA->CRH|=0X000008B0;//IO状态设置
		  
	RCC->APB2RSTR|=1<<14;   //复位串口1
	RCC->APB2RSTR&=~(1<<14);//停止复位	   	   
	//波特率设置
 	USART1->BRR=mantissa; // 波特率设置	 
	USART1->CR1|=0X200C;  //1位停止,无校验位.


#ifdef EN_USART1_RX		  //如果使能了接收
	//使能接收中断
	USART1->CR1|=1<<8;    //PE中断使能
	USART1->CR1|=1<<5;    //接收缓冲区非空中断使能	    	
	MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级 
#endif

/********************************************************************************/
//串口2 的初始化
//PORTA口时钟 //串口2对应的Tx为PA2	RX为PA3
 	temp2=(float)(pclk2/2*1000000)/(bound*16);//得到USARTDIV
	mantissa2=temp2;				 //得到整数部分
	fraction2=(temp2-mantissa2)*16; //得到小数部分	 
    mantissa2<<=4;
	mantissa2+=fraction2;
	
    RCC->APB2ENR|=1<<2;   //使能PORTA口时钟 //串口2对应的Tx为PA2	RX为PA3
	RCC->APB1ENR|=1<<17;  //使能串口2时钟 
	GPIOA->CRL&=0XFFFF00FF;    //设置PC10为输出模式 PC11为输入模式
	GPIOA->CRL|=0X00008B00;//IO状态设置
		  
	RCC->APB1RSTR|=1<<17;   //复位串口3
	RCC->APB1RSTR&=~(1<<17);//停止复位	   	   
	//波特率设置
 	USART2->BRR=mantissa2; // 波特率设置 串口2-5使用的晶振都是36Mhz的 串口2~5使用的是pclk1,为36M,而不是串口1的72M 	 
	USART2->CR1|=0X200C;  //1位停止,无校验位.

#ifdef EN_USART2_RX		  //如果使能了接收
	//使能接收中断
	USART2->CR1|=1<<8;    //PE中断使能
	USART2->CR1|=1<<5;    //接收缓冲区非空中断使能	    	
	MY_NVIC_Init(3,3,USART2_IRQChannel,1);//组1,最低优先级 
#endif

/********************************************************************************/
//串口3 的初始化		   
	temp3=(float)(pclk2/2*1000000)/(bound*16);//得到USARTDIV
	mantissa3=temp3;				 //得到整数部分
	fraction3=(temp3-mantissa3)*16; //得到小数部分	 
    mantissa3<<=4;
	mantissa3+=fraction3;
	
    RCC->APB1ENR|=1<<3;   //使能PORTC口时钟  //串口3对应的Tx为PB10	RX为PB11
	RCC->APB1ENR|=1<<18;  //使能串口3时钟 
	GPIOB->CRH&=0XFFFF00FF;    //设置PB10为输出模式 PB11为输入模式
	GPIOB->CRH|=0X00008B00;//IO状态设置
		  
	RCC->APB1RSTR|=1<<18;   //复位串口3
	RCC->APB1RSTR&=~(1<<18);//停止复位	   	   
	//波特率设置
 	USART3->BRR=mantissa3; // 波特率设置 串口2-5使用的晶振都是36Mhz的 串口2~5使用的是pclk1,为36M,而不是串口1的72M 	 
	USART3->CR1|=0X200C;  //1位停止,无校验位.

#ifdef EN_USART3_RX		  //如果使能了接收
	//使能接收中断
	USART3->CR1|=1<<8;    //PE中断使能
	USART3->CR1|=1<<5;    //接收缓冲区非空中断使能	    	
	MY_NVIC_Init(3,3,USART3_IRQChannel,1);//组1,最低优先级 
#endif
}
 <pre name="code" class="cpp">timer.h
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//通用定时器 驱动代码			   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/12/03
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
// 	  

//通过改变TIM3->CCR2的值来改变占空比,从而控制LED0的亮度
#define LED0_PWM_VAL TIM3->CCR2 

void Timerx_Init(u16 arr,u16 psc);
void PWM_Init(u16 arr,u16 psc);
#endif

timer.c

#include "timer.h"
#include "led.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//通用定时器 驱动代码			   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/12/03
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
// 	  

//定时器3中断服务程序	 
void TIM3_IRQHandler(void)
{ 		    		  			    
	if(TIM3->SR&0X0001)//溢出中断
	{
		LED1=!LED1;			    				   				     	    	
	}				   
	TIM3->SR&=~(1<<0);//清除中断标志位 	    
}
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void Timerx_Init(u16 arr,u16 psc)
{
	RCC->APB1ENR|=1<<1;//TIM3时钟使能    
 	TIM3->ARR=arr;  //设定计数器自动重装值//刚好1ms    
	TIM3->PSC=psc;  //预分频器7200,得到10Khz的计数时钟
	//这两个东东要同时设置才可以使用中断
	TIM3->DIER|=1<<0;   //允许更新中断				
	TIM3->DIER|=1<<6;   //允许触发中断
		  							    
	TIM3->CR1|=0x01;    //使能定时器3
  	MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//抢占1,子优先级3,组2									 
}

//TIM3 PWM部分
//正点原子@ALIENTEK
//2010/6/2	 

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void PWM_Init(u16 arr,u16 psc)
{
		 					 	
/********************************************************************************/
//总体是3部分
//1、使能定时器时钟,因为PWM是由定时器产生的。
//   其实这里用到了GPIOA的引脚,因此也需要使能GPIOA的时钟的,但是在led.c文件中,已经设置过了,所以这里省略了
//   另外这里使用的GPIO输出PWM是复用,所以需要配置GPIO口的默认复用功能,这里请注意,一定是默认的复用功能,可以查看led.c中的3个步骤
//2、配置定时器的配置,TIM3->结构后的,是对定时器3的配置
//3、使能定时器外设,TIM3->CR1|=0x01; 

	//此部分需手动修改IO口设置
	RCC->APB1ENR|=1<<1;       //TIM3时钟使能
	    
	//下面这两句仅仅是为了,用跳帽把PA7与PA8连接起来,用led灯来观察PWM输出,可以没有的
	GPIOA->CRH&=0XFFFFFFF0;//PA8输出
	GPIOA->CRH|=0X00000004;//浮空输入	这里的浮空输入是为了防止干扰PA8的输出,因为PA8在ministm32上是连接的led灯
	  	
	GPIOA->CRL&=0X0FFFFFFF;//PA7输出
	GPIOA->CRL|=0XB0000000;//复用功能输出 	  
	GPIOA->ODR|=1<<7;//PA7上拉	

	TIM3->ARR=arr;//设定计数器自动重装值 
	TIM3->PSC=psc;//预分频器不分频
	
	//TIM3->CCMR1|=7<<12;  //CH2 PWM2模式			这个作用在板子上的灯DS0
	TIM3->CCMR1|=6<<12;  //CH2 PWM2模式	与上面一句的极性相反 如果用这个控制舵机,请使用这个PWM,输出正电平方波	 
	TIM3->CCMR1|=1<<11; //CH2预装载使能	   

	TIM3->CCER|=1<<4;   //OC2 输出使能	   

	TIM3->CR1=0x8000;   //ARPE使能 
	TIM3->CR1|=0x01;    //使能定时器3 
		
/********************************************************************************/
//通用定时器4 1通道(PB6)和2通道(PB7)

	RCC->APB1ENR|=1<<2;//TIM4时钟使能    
	RCC->APB2ENR|=1<<3;//这里必须有这一个GPIO口的使能,GPIOA已经在led.c中定义过了,可是GPIO 的B口还没有
								  
	GPIOB->CRL&=0X00FFFFFF;//清掉PB7 PB6位原来的设置,同时不影响其他位的设置
	GPIOB->CRL|=0XBB000000;//复用功能输出 	  PB7的默认复用功能为 TIM4的2通道
	GPIOB->ODR|=1<<7;//PB7
	GPIOB->ODR|=1<<6;//PB6

	TIM4->ARR=arr;//设定计数器自动重装值 
	TIM4->PSC=psc;//预分频器不分频

	//这里进行说明,CCMR1寄存器是配置模式的,总共可以设置为7中模式,CCMR1控制CH1和CH2 CCMR2控制CH3和CH4
	//TIM4->CCMR1|=7<<12;  //
	TIM4->CCMR1|=6<<12;  //PB7的默认复用功能为 TIM4的2通道 CH2 PWM2模式且极性为正电平方波
	TIM4->CCMR1|=6<<4; 	  //CH1 PWM2模式
	
	TIM4->CCMR1|=1<<11; //CH2预装载使能
	TIM4->CCMR1|=1<<3;	 //ch1预装载使能 是PB6口		 
		
	TIM4->CCER|=1<<0;	 //输出使能	 这个寄存器控制着各个输入输出通道的开关,因此如果要有输出必须使能
	TIM4->CCER|=1<<4;   //输出使能
		   
	TIM4->CR1=0x8000;   //ARPE使能 
	TIM4->CR1|=0x01;    //使能定时器4  										  
}  	 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值