配置时钟,延时函数,均使用正点原子的SYSTEM文件
硬件:正点原子探索者,STLINK调试
系统时钟配置步骤
正点原子,时钟配置函数(我都是直接把sys.c和sys.h拷贝过来,直接使用)
//设置向量表偏移地址
//NVIC_VectTab:基址
//Offset:偏移量
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab,u32 Offset)
{
SCB->VTOR=NVIC_VectTab|(Offset&(u32)0xFFFFFE00);//设置NVIC的向量表偏移寄存器,VTOR低9位保留,即[8:0]保留。
}
//时钟设置函数
//Fvco=Fs*(plln/pllm);
//Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
//Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));
//Fvco:VCO频率
//Fsys:系统时钟频率
//Fusb:USB,SDIO,RNG等的时钟频率
//Fs:PLL输入时钟频率,可以是HSI,HSE等.
//plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
//pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
//pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
//pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
//外部晶振为8M的时候,推荐值:plln=336,pllm=8,pllp=2,pllq=7.
//得到:Fvco=8*(336/8)=336Mhz
// Fsys=336/2=168Mhz
// Fusb=336/7=48Mhz
//返回值:0,成功;1,失败。
u8 Sys_Clock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
u16 retry=0;
u8 status=0;
RCC->CR|=1<<16; //HSE 开启
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//等待HSE RDY
if(retry==0X1FFF)status=1; //HSE无法就绪
else
{
RCC->APB1ENR|=1<<28; //电源接口时钟使能
PWR->CR|=3<<14; //高性能模式,时钟可到168Mhz
RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);//HCLK 不分频;APB1 4分频;APB2 2分频.
RCC->CR&=~(1<<24); //关闭主PLL
RCC->PLLCFGR=pllm|(plln<<6)|(((pllp>>1)-1)<<16)|(pllq<<24)|(1<<22);//配置主PLL,PLL时钟源来自HSE
RCC->CR|=1<<24; //打开主PLL
while((RCC->CR&(1<<25))==0);//等待PLL准备好
FLASH->ACR|=1<<8; //指令预取使能.
FLASH->ACR|=1<<9; //指令cache使能.
FLASH->ACR|=1<<10; //数据cache使能.
FLASH->ACR|=5<<0; //5个CPU等待周期.
RCC->CFGR&=~(3<<0); //清零
RCC->CFGR|=2<<0; //选择主PLL作为系统时钟
while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.
}
return status;
}
//系统时钟初始化函数
//plln:主PLL倍频系数(PLL倍频),取值范围:64~432.
//pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
//pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
//pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
RCC->CR|=0x00000001; //设置HISON,开启内部高速RC振荡
RCC->CFGR=0x00000000; //CFGR清零
RCC->CR&=0xFEF6FFFF; //HSEON,CSSON,PLLON清零
RCC->PLLCFGR=0x24003010; //PLLCFGR恢复复位值
RCC->CR&=~(1<<18); //HSEBYP清零,外部晶振不旁路
RCC->CIR=0x00000000; //禁止RCC时钟中断
Sys_Clock_Set(plln,pllm,pllp,pllq);//设置时钟
//配置向量表
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(1<<29,0x0);
#else
MY_NVIC_SetVectorTable(0,0x0);
#endif
}
时钟与外设
使能则相应位置一
RCC->AHB1ENR |= 0x00000008; //使能GPIOD时钟
RCC->APB2ENR |= (1<<14); //使能syscfg时钟
GPIO
设置步骤:
使能相关时钟
设置相应的IO口为输入或输出 BSRRH BSRRL
设置输入输出的类型 OTYPER
设置输出的速度(如果设置为输入,此步跳过) OSPEEDR
如果输出速度>=50M,开启补偿单元 SYSCFG->CMPCR
设置上拉下拉寄存器 PUPDR
注意:
IDR寄存器,(只读),对GPIO输入的读取
ODR寄存器,对GPIO输出的读写
BSSR寄存器,(只写),对GPIO输出,低16位,输出高电平,高16位,输出低电平
//reset register GPIOx_BSRRH, write only
//set register GPIOx_BSRRL, write only
GPIO F9,F10 交替闪烁
#include #include #include int main () { Stm32_Clock_Init(336,8,2,7); //系统时钟 delay_init(48); RCC->AHB1ENR |= 0x00000020; //使能GPIOF时钟 GPIOF->MODER &= 0x00000000; //设置F9,F10 0001 0100 0000 0000 0000 0000 GPIOF->MODER |= 0x00140000; GPIOF->OTYPER &= 0x00000600; //设置F9,F10推挽输出 GPIOF->OSPEEDR &= 0x00000000; //F9,F10 速度50m 0010 1000 0000 0000 0000 0000 GPIOF->OSPEEDR |= 0x00280000; //GPIOF->PUPDR &= 0x00280000; //10下拉 00无 //GPIOF->PUPDR &= 0x00140000; //01上拉 while(1) { GPIOF->BSRRH = 0x0200; //0000 0000 0010 delay_ms(1000); GPIOF->BSRRL = 0x0200; //0000 0000 0010 GPIOF->BSRRH = 0x0400; delay_ms(1000); GPIOF->BSRRL = 0x0400; // GPIOF->ODR=0x00000600; // delay_ms(1000); // GPIOF->ODR=0x00000000; // delay_ms(1000); } } 串口与GPIO复用 GPIO复用功能映射表,只给出PORTA,B,C 根据表中找出对应外设的复用引脚,及复用功能选择位,AFn。 GPIO复用: 由两个寄存器控制,GPIOx_AFRH(高八位),GPIOx_AFRL(低八位)。 在程序中,GPIOB->AFR[0]表示GPIOx_AFRL(低八位), GPIOB->AFR[1]表示GPIOx_AFRH(高八位)。 找到对应的引脚y,写入AFn。 比如串口三对应的复用功能是AF7,引脚是B10,11。则设置引脚的输出类型,速度,上拉下拉。 引脚位于高八位,写入GPIOx_AFRH,GPIOB->AFR[1] = 0x00007700 串口三 内容回显 内容以回车(0x0D)结束 设置步骤: 使能相关时钟 RCC->AHB1ENR|=1<<1; //使能PORTB口时钟 RCC->APB1ENR|=1<<18; //使能串口3时钟 设置相应的IO口为复用输出 GPIO_Set(GPIOB,PIN10|PIN11,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PB10,PB11,复用功能,上拉输出 GPIO_AF_Set(GPIOB,10,7); //PB10,AF7 GPIO_AF_Set(GPIOB,11,7); //PB11,AF7 波特率设置 //计算波特率 float temp; u16 mantissa; u16 fraction; temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV,OVER8设置为0 mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分,OVER8设置为0 mantissa<<=4; mantissa+=fraction; //串口设置 USART3->BRR=mantissa; //波特率设置 USART3->CR1|=1<<3; //串口发送使能 USART3->CR1|=1<<2; //串口接收使能 USART3->CR1|=1<<5; //接收缓冲区非空中断使能 USART3->CR1|=1<<13; //串口使能 //中断优先级 MY_NVIC_Init(0,0,USART3_IRQn,2);//组2,优先级0,0,最高优先级 状态寄存器 USART3->SR 数据寄存器 USART3->DR 缓冲区数组内容清空 memset(USART3_RX_BUF,0,USART3_MAX_RECV_LEN) 完整代码: #include #include #include #include "string.h" u8 ok_to_send; //可以发送的标志 u8 Rx_data_counter; #define USART3_MAX_RECV_LEN 400 //最大接收缓存字节数 //串口接收缓存区 u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节. u8 Rx_data_counter=0; u8 ok_to_send=0; void USART3_IRQHandler(void) { if(USART3->SR & (1<<5)) //接收数据寄存器非空 { USART3_RX_BUF[Rx_data_counter] = USART3->DR; Rx_data_counter++; if(USART3_RX_BUF[Rx_data_counter-1] ==0x0D) { Rx_data_counter = 0; ok_to_send=1; } } } //初始化IO 串口3 //pclk1:PCLK1时钟频率(Mhz) //bound:波特率 void usart3_init(u32 pclk1,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV,OVER8设置为0 mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分,OVER8设置为0 mantissa<<=4; mantissa+=fraction; RCC->AHB1ENR|=1<<1; //使能PORTB口时钟 RCC->APB1ENR|=1<<18; //使能串口3时钟 GPIO_Set(GPIOB,PIN10|PIN11,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PB10,PB11,复用功能,上拉输出 GPIO_AF_Set(GPIOB,10,7); //PB10,AF7 GPIO_AF_Set(GPIOB,11,7); //PB11,AF7 //波特率设置 USART3->BRR=mantissa; // 波特率设置 USART3->CR1|=1<<3; //串口发送使能 USART3->CR1|=1<<2; //串口接收使能 USART3->CR1|=1<<5; //接收缓冲区非空中断使能 USART3->CR1|=1<<13; //串口使能 MY_NVIC_Init(0,0,USART3_IRQn,2);//组2,优先级0,0,最高优先级 } int main() { u8 j=0; Stm32_Clock_Init(336,8,2,7); usart3_init(42,9600);//初始化串口3为:9600,波特率. while(1) { if(ok_to_send==1) { for(j=0;j USART3->DR=USART3_RX_BUF[j]; while((USART3->SR&0X40)==0);//循环发送,直到发送完毕 if( USART3_RX_BUF[j] ==0x0D) { ok_to_send=0; j=0; memset(USART3_RX_BUF,0,USART3_MAX_RECV_LEN); } } } } } 注意: 串口数据的读写,可以看到,是以8bit,一个字节为单位来读写的。利用DR寄存器,对DR进行读取,即DR赋值给别人,BUFF=DR。对DR进行写入,即别人赋值给DR,DR=BUFF。 再利用状态寄存器,SR来读取状态信息控制。 能否像小船博主一样,全部用寄存器来设置呢? https://blog.csdn.net/w471176877/article/details/7957187 也就是关于GPIO复用 注释了GPIO设置的三个函数,完全用寄存器来设置 // GPIO_Set(GPIOB,PIN10|PIN11,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);//PB10,PB11,复用功能,上拉输出 // GPIO_AF_Set(GPIOB,10,7); //PB10,AF7 // GPIO_AF_Set(GPIOB,11,7); //PB11,AF7 GPIOB->AFR[1] = 0x00007700;//选择PB10,11复用功能 GPIOB->MODER &= 0xFF0FFFFF; //设置PB10,11,复用模式 GPIOB->MODER |= 0x00A00000; GPIOB->OSPEEDR &= 0xFFCFFFFF; //PB10速度50m GPIOB->OSPEEDR |= 0x00200000; GPIOB->PUPDR &= 0xFFCFFFFF; //PB10 GPIOB->PUPDR |= 0x00100000; 中断优先级函数也用寄存器来替代了 //MY_NVIC_Init(0,0,USART3_IRQn,2);//组2,优先级0,0,最高优先级 SCB->AIRCR = 0x05FA0000 | 0x400; //中断优先级分组 抢占:响应=3:1 NVIC->IP[39] = 0xf0; //最低抢占优先级,最低响应优先级1111 NVIC->ISER[1] |= (1<<(39-32)); //使能中断线39,也就是usart3中断 除了时钟树配置,其它都自己用寄存器来配置了。 #include #include #include #include "string.h" u8 suffer[100]; u8 ok_to_send; u8 Rx_data_counter; #define USART3_MAX_RECV_LEN 400 //最大接收缓存字节数 //串口接收缓存区 u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节. u8 Rx_data_counter=0; u8 ok_to_send=0; void USART3_IRQHandler(void) { if(USART3->SR & (1<<5)) //接收数据寄存器非空 { USART3_RX_BUF[Rx_data_counter] = USART3->DR; Rx_data_counter++; if(USART3_RX_BUF[Rx_data_counter-1] ==0x0D) { Rx_data_counter = 0; ok_to_send=1; } } } //初始化IO 串口3 //pclk1:PCLK1时钟频率(Mhz) //bound:波特率 void usart3_init(u32 pclk1,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV,OVER8设置为0 mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分,OVER8设置为0 mantissa<<=4; mantissa+=fraction; RCC->AHB1ENR|=1<<1; //使能PORTB口时钟 RCC->APB1ENR|=1<<18; //使能串口3时钟 GPIOB->AFR[1] = 0x00007700;//选择PB10,11复用功能 GPIOB->MODER &= 0xFF0FFFFF; //设置PB10,11,复用模式 GPIOB->MODER |= 0x00A00000;
上一篇:STM32F407 纯寄存器操作定时器,PWM,ADC(专治花里胡哨)
下一篇:stm32 SCB->AIRCR 寄存器和中断优先级寄存器使用理解
推荐阅读最新更新时间:2024-11-10 10:43
设计资源 培训 开发板 精华推荐
- LTM4643EV 4V 至 20V 输入、四路 0.9V、1V、1.2V 和 1.5V 输出 DC/DC 降压稳压器的典型应用
- DC1460A、LTC3620EDC 演示板、超低功耗 15mA 高效率降压型开关稳压器
- 使用 ON Semiconductor 的 NCP9004FCT1G 的参考设计
- L4931 具有抑制功能的超低压降稳压器的典型应用
- 用于消费电子产品的 100W、24V 交流转直流单路输出电源
- 具有温度监控功能的 LTM4648EY 单路 10A 设计的典型应用电路
- NB-IoT 物联网开发平台
- TB62737FUG 用于 2 至 6 WLED 驱动器的升压 DC-DC 转换器的典型应用
- MPC56xxVXBOARDS: MPC56xx VertiCal校准板
- 使用 Ricoh Electronic Devices Co., Ltd 的 R1240K003 的参考设计