×
单片机 > 单片机程序设计 > 详情

stm32-led-串口-PWM

发布时间:2020-05-18 发布时间:
|

因为项目需要,学习了一下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

#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

#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("%dn",imgCenterX1);

//

// imgCenterY1=atoi(imgCenterY);

// //printf("%dn",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("%dn",imgCenterX1);

 

imgCenterY1=atoi(imgCenterY);

//printf("%dn",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("%dn",imgCenterX1);

//

// imgCenterY1=atoi(imgCenterY);

// //printf("%dn",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

}

 

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    

}   




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机中高阻态的实质及意义