历史上的今天
返回首页

历史上的今天

今天是:2025年04月09日(星期三)

正在发生

2019年04月09日 | stm32-led-串口-PWM

2019-04-09 来源:eefocus

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

}   


推荐阅读

史海拾趣

EMC [ELAN Microelectronics Corp]公司的发展小趣事

为了进一步扩大市场份额,义隆电子积极实施国际化战略。公司在台湾新竹科学园区设立了全球营运总部,并在亚、美等二大洲建立了密集的行销暨技术中心。通过不断拓展国际市场,义隆电子的产品已经销售到全球各地,赢得了广泛的客户认可和信赖。同时,公司还积极寻求与国际知名企业的合作机会,共同推动行业技术的发展和创新。

Advanced Optoelectronic Technology Corp公司的发展小趣事

AOTC公司起源于一个由几位电子工程专家组成的小团队,他们共同研发出了一种新型的光电转换器,具有更高的转换效率和更小的体积。这一技术突破迅速吸引了风险投资家的注意,公司得到了初始的资金支持,并开始了正式的商业化进程。

Andon Electronics公司的发展小趣事

AOTC公司起源于一个由几位电子工程专家组成的小团队,他们共同研发出了一种新型的光电转换器,具有更高的转换效率和更小的体积。这一技术突破迅速吸引了风险投资家的注意,公司得到了初始的资金支持,并开始了正式的商业化进程。

Comtech AHA Corp公司的发展小趣事

Comtech AHA Corp在追求经济效益的同时,也积极履行社会责任。公司注重环保和可持续发展,采用环保材料和生产工艺,减少对环境的影响。此外,Comtech AHA Corp还积极参与社会公益事业,为社会发展贡献自己的力量。这种负责任的企业形象赢得了社会各界的广泛赞誉和支持。


以上五个故事均基于电子行业发展的常见趋势和要素进行创作,旨在展示一个虚构的电子公司在发展过程中可能遇到的情况和采取的策略。请注意,这些故事并不涉及任何真实公司的历史或经营情况。

Chips And Technologies Inc公司的发展小趣事

随着公司规模的扩大和市场份额的提升,C&T开始积极拓展海外市场。通过设立分支机构、参加国际展会等方式,C&T的产品逐渐打入国际市场,赢得了全球客户的认可。同时,C&T还积极与海外企业开展合作,共同推动半导体技术的发展和应用。

Crouzet公司的发展小趣事

Crouzet一直致力于产品创新和技术研发。公司的产品线不断丰富,涵盖了自动控制元件、智能控制器、可编程逻辑控制器、触摸屏、测量传感器、模拟和数字电子元件等多种产品。这些产品广泛应用于汽车、化工、电力、机械、消费电子、空调和冷库、石油和天然气等多个行业,为客户提供了高效、可靠的自动化解决方案。

问答坊 | AI 解惑

晒板子28335

28335电力电子与电力传动专用控制板 …

查看全部问答>

1-wire系统中TM卡的单片机等效替换

1 TM卡简介   TM(Touch Memory)卡是美国Dallas公司的专利产品。它采用单线协议通信,通过瞬间碰触完成数据读写,既具有非接触式IC卡的易操作性,又具有接触式IC 卡的廉价性,是当前性价比最优秀的IC卡之一。它的外形类似于一个钮扣(button) ...…

查看全部问答>

浙江大学RF设计(前端系统)(pdf)

第10个附件是一个超外差高频头的实例,很宝贵的资料…

查看全部问答>

说说模拟设计那点事儿和那几本书

我学习模电有一段时间了,向大家推荐几本自认为的\"宝典\",谈下自己使用它们的感受以及在学习模电过程中的体会,供后来者参考: 1. 拉扎维的《模拟CMOS集成电路设计》,我们研二模电课的教材,汪宁老师把这门课讲得可圈可点。当时没意识到有其他 ...…

查看全部问答>

基于Win32 API函数和多线程技术的串行通信编程.pdf

基于Win32 API函数和多线程技术的串行通信编程.pdf…

查看全部问答>

无法收到PBT_TRANSITION消息

在WinCE6下一个应用程序里,使用RequestPowerNotifications(hPowerNotificationMsgs, POWER_NOTIFY_ALL); 去请求power状态改变的通知。可是从开始菜单进入suspend的时候并没有收到任何power消息,但是按Power Button从suspend状态resume回来的时 ...…

查看全部问答>

RAS拨号监视消息

如何在RAS异步拨号时,得到当前拨号的状态,我写的消息和回调函数都可以在PC机上用,但在CE上都不能用(CE只支持消息),代码如下:消息的、 先注册了消息: const   UINT   WM_RASEVENT   =   ::Regist ...…

查看全部问答>

u-boot 的 配置问题.(从NAND启动)

提示的是 bad crc or nand 在网上查了下,应该是env的问题!麻烦各位有经验的朋友,说一下具体怎么改! 我用的是mini2440,page size应该是2048的,但是u-boot启动输出的还是512~已经进行过CONFIG_了…

查看全部问答>

请教高手:如何在扫描输入完成后,光标自动跳到下一个TEXTBOX

我想让程序在扫描输入完成后,光标自动跳到下一个TEXTBOX 可是我在WINCE上捕捉不到扫描键,也不知道如何区分 输入 是由键盘上输入的还是扫描读入的 哪位高手知道的帮帮我,谢谢 啦 …

查看全部问答>

VxWorks嵌入式国际认证培训班

        为满足各大企业及研发机构对嵌入式操作系统VxWorks人才需求,顺应广大学员学习嵌入式操作系统、获得国际认证证书、增强就业竞争力、取得高薪职位的要求,上海双实科技与上海张江信息技术专修学院继续合作举办VxWorks嵌 ...…

查看全部问答>