ALIENTEK精英STM32F103开发板 实验0测试程序详解

#include "sys.h"

#include "usart.h"

#include "delay.h"

//ALIENTEK精英STM32F103开发板 实验0

//新建工程 实验

//技术支持:www.openedv.com

//广州市星翼电子科技有限公司

int main(void)

{

u8 t=0; //见注释1

Stm32_Clock_Init(9); //1.系统时钟设置

delay_init(72); //2.延时初始化

uart_init(72,115200); //3.串口初始化为115200

while(1)

{

printf("t:%d\r\n",t);

delay_ms(500);

t++;

}

}

程序详解:

1.系统时钟设置

//系统时钟初始化函数

//pll:选择的倍频数,从2开始,最大值为16

void Stm32_Clock_Init(u8 PLL)

{

unsigned char temp=0;

MYRCC_DeInit(); //1.1复位并配置向量表

RCC->CR|=0x00010000; //外部高速时钟使能HSEON--HSE振荡器开启

while(!(RCC->CR>>17));//等待外部时钟就绪--外部高速时钟就绪标志 1:外部4-16MH振//荡器就绪,此语句应改为:while(!(RCC->CR>>17)&0X01);

RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;--低速APB预分频 位10:8 //100: HCLK 2分频

PLL-=2; //抵消2个单位(因为是从2开始的,设置0就是2)

RCC->CFGR|=PLL<<18; //设置PLL值 2~16--位21:18 PLL倍频系数

RCC->CFGR|=1<<16; //PLLSRC ON -- PLL输入时钟源 1: HSE时钟作为PLL输入时钟。

FLASH->ACR|=0x32; //1.2闪存访问控制寄存器FLASH 2个延时周期--位2~0 LATENCY:时延 这些位表示//SYSCLK(系统时钟)周期与闪存访问时间的比例

//000:零等待状态,当 0 < SYSCLK ≤ 24MHz

//001:一个等待状态,当 24MHz < SYSCLK ≤ 48MHz

//010:两个等待状态,当 48MHz < SYSCLK ≤ 72MHz

//--位3 HLFCYA:闪存半周期访问使能 0:禁止半周期访问;

//--位4 PRFTBE:预取缓冲区使能 1:启用预取缓冲区。

//--位5 PRFTBS:预取缓冲区状态 1:预取缓冲区开启。

RCC->CR|=0x01000000; //PLLON--位24 PLLON: PLL使能 1: PLL使能

while(!(RCC->CR>>25));//等待PLL锁定--位25 PLLRDY: PLL时钟就绪标志 1: PLL锁定。

RCC->CFGR|=0x00000002;//PLL作为系统时钟--位1:0 SW[1:0]:系统时钟切换

while(temp!=0x02) //等待PLL作为系统时钟设置成功

{

temp=RCC->CFGR>>2;

temp&=0x03;

}

}

    1. 复位并配置向量表

//不能在这里执行所有外设复位!否则至少引起串口不工作.

//把所有时钟寄存器复位

void MYRCC_DeInit(void)

{

RCC->APB1RSTR = 0x00000000;//复位结束--APB1外设复位寄存器 0为无作用

RCC->APB2RSTR = 0x00000000;//--APB2 外设复位寄存器 0为无作用

RCC->AHBENR = 0x00000014; //睡眠模式闪存和SRAM时钟使能.其他关闭--AHB外//设时钟使能寄存器,1:睡眠模式时SRAM时钟开启,1:睡眠模式时闪存接口电路时//钟开启

RCC->APB2ENR = 0x00000000; //外设时钟关闭.--APB2 外设时钟使能寄存器

RCC->APB1ENR = 0x00000000; //--APB1 外设时钟使能寄存器

RCC->CR |= 0x00000001; //使能内部高速时钟HSION--时钟控制寄存器,1:内部//8MHz振荡器开启。

RCC->CFGR&=0xF8FF0000;//复位

//时钟配置寄存器SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]

//--00: HSI作为系统时钟;AHB预分频 0xxx: //SYSCLK不分频;低速APB预分频 0xx: HCLK不分频;高速APB预分频 0xx: HCLK不分//频;ADC预分频 00: PCLK2 2分频后作为ADC时钟;微控制器时钟输出 100:系统时钟//(SYSCLK)输出

RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON--外部高速时钟使能 0: HSE

//振荡器关闭;时钟安全系统使能 0:时钟监测器关闭;PLL使能 0: PLL关闭;

RCC->CR &= 0xFFFBFFFF; //复位HSEBYP--外部高速时钟旁路 0:外部4-16MHz振荡//器没有旁路;

RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE

//--PLL输入时钟源 0: HSI振荡器时钟经2分频后作为PLL输入时钟; HSE分频器作为PLL输入 0: HSE不分频

//--PLL倍频系数 0000: PLL 2倍频输出;USB预分频 0: //PLL时钟1.5倍分频作为USB时钟

RCC->CIR = 0x00000000; //关闭所有中断--时钟中断寄存器

//配置向量表

#ifdef VECT_TAB_RAM

MY_NVIC_SetVectorTable(0x20000000, 0x0);//注释1.1.1

#else

MY_NVIC_SetVectorTable(0x08000000,0x0);

#endif

}

1.1.1//设置向量表偏移地址

//NVIC_VectTab:基址

//Offset:偏移量

void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)

{

SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//设置NVIC的向量表偏移寄存器

//用于标识向量表是在CODE区还是在RAM区

}

SCB 为 MDK 定义的一个寄存器组,里面包含了很多与内核相关的控制器, 该结构体在core_m3.h 里面

1.2 FLASH->ACR|=0x32; //闪存访问控制寄存器

2.延时初始化

//初始化延迟函数

//当使用OS的时候,此函数会初始化OS的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(u8 SYSCLK)

{

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

u32 reload;

#endif

SysTick->CTRL&=~(1<<2); //SYSTICK使用外部时钟源

fac_us=SYSCLK/8; //不论是否使用OS,fac_us都需要使用

#if SYSTEM_SUPPORT_OS //如果需要支持OS.

reload=SYSCLK/8; //每秒钟的计数次数 单位为K

reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间

//reload为24位寄存器,最值:16777216,

//在72M下,约合1.86s左右

fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位

SysTick->CTRL|=1<<1; //开启SYSTICK中断

SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次

SysTick->CTRL|=1<<0; //开启SYSTICK

#else

fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数

#endif

}

3.串口初始化

//初始化IO 串口1

//pclk2:PCLK2时钟频率(Mhz)

//bound:波特率

void uart_init(u32 pclk2,u32 bound)

{

float temp;

u16 mantissa;//--尾数

u16 fraction;//--分数

temp=(float)(pclk2*1000000)/(bound*16);//得到//USARTDIV--Baud=fck/(16*USARTDIV),USARTDIV为16进制数,分尾数和分数

mantissa=temp; //得到整数部分

fraction=(temp-mantissa)*16; //得到小数部分

mantissa<<=4;//

mantissa+=fraction; //--填入的16进制数

RCC->APB2ENR|=1<<2; //使能PORTA口时钟--位2 IOPAEN: IO端口A时钟使能

//(I/O port A clock enable)

RCC->APB2ENR|=1<<14; //使能串口时钟 --位14 USART1EN: USART1时钟使能 (USART1 clock enable)

GPIOA->CRH&=0XFFFFF00F;//IO状态设置--设置TX RX 口的推挽输出、浮空输入模式

GPIOA->CRH|=0X000008B0;//IO状态设置

RCC->APB2RSTR|=1<<14; //复位串口1--位14 USART1RST: USART1复位 1:复位USART1。

RCC->APB2RSTR&=~(1<<14);//停止复位

//波特率设置

USART1->BRR=mantissa; // 波特率设置--位3:0 DIV_Fraction[3:0]: USARTDIV的小数

//部分 位15:4 DIV_Mantissa[11:0]: USARTDIV的整数部分

USART1->CR1|=0X200C; //1位停止,无校验位.

#if EN_USART1_RX //如果使能了接收

//使能接收中断

USART1->CR1|=1<<5; //接收缓冲区非空中断使能--位5 RXNEIE:接收缓冲区非空中

//断使能 1:当USART_SR中的ORE或者RXNE为'1'时,产生USART中断。

MY_NVIC_Init(3,3,USART1_IRQn,2);//3.1 组2,最低优先级

#endif

}

3.1 MY_NVIC_Init(3,3,USART1_IRQn,2);

//设置NVIC

//NVIC_PreemptionPriority:抢占优先级

//NVIC_SubPriority :响应优先级

//NVIC_Channel :中断编号

//NVIC_Group :中断分组 0~4

//注意优先级不能超过设定的组的范围!否则会有意想不到的错误

//组划分:

//组0:0位抢占优先级,4位响应优先级

//组1:1位抢占优先级,3位响应优先级

//组2:2位抢占优先级,2位响应优先级

//组3:3位抢占优先级,1位响应优先级

//组4:4位抢占优先级,0位响应优先级

//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先

void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)

{

u32 temp;

MY_NVIC_PriorityGroupConfig(NVIC_Group);//3.1.1设置分组

temp=NVIC_PreemptionPriority<<(4-NVIC_Group);//--//(4-NVIC_Group) 组0 左移4位 0

//位抢占 ,组1 左移3位 1位抢占,组2 左移2位 2位抢占,组3 左移1位 3位抢//占,组4 左移0位,4位抢占

temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);//--(0x0f>>NVIC_Group)限定位 组0 1111 //4位响应,组1 0111 3位响应 , 组2 0011 2位响应, 组3 0001 1位响应, 组//4 0000,0位响应

temp&=0xf; //取低四位

NVIC->ISER[NVIC_Channel/32]|=(1<<NVIC_Channel%32);//使能中断位(要清除的话,相反操//作就OK)--ISER[0]的 bit0~bit31 分别对应中断 0~31

NVIC->IP[NVIC_Channel]|=temp<<4; //设置响应优先级和抢断优先级--设置响应优//先级和抢断优先级

}

3.1.1 MY_NVIC_PriorityGroupConfig(NVIC_Group);

//设置NVIC分组

//NVIC_Group:NVIC分组 0~4 总共5组

void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)

{

u32 temp,temp1;

temp1=(~NVIC_Group)&0x07;//取后三位

temp1<<=8;

temp=SCB->AIRCR; //读取先前的设置--寄存器的[10:8]3 位就是 PRIGROUP 的定义位,//它的值规定了系统中

//有多少个抢先级中断和子优先级中断,此值与分组值为取反关系

temp&=0X0000F8FF; //清空先前分组

temp|=0X05FA0000; //写入钥匙

temp|=temp1;

SCB->AIRCR=temp; //设置分组

}

注释1.

typedef struct

{

__O union

{

__O uint8_t u8; /*!< Offset: ITM Stimulus Port 8-bit */

__O uint16_t u16; /*!< Offset: ITM Stimulus Port 16-bit*/

__O uint32_t u32; /*!< Offset: ITM Stimulus Port 32-bit */

} PORT [32]; /*!< Offset: 0x00 ITM Stimulus Port Registers*/

uint32_t RESERVED0[864];

__IO uint32_t TER; /*!< Offset: ITM Trace Enable Register */

// typedef unsigned int uint32_t;

uint32_t RESERVED1[15];

__IO uint32_t TPR; /*!< Offset: ITM Trace Privilege Register*/

Identification Register #2 */

.....(此处省略部分内容)

__I uint32_t CID3; /*!< Offset: ITM Component Identification Register #3 */

} ITM_Type;

共用体(参考"共用体"百科词条)是一种特殊形式的变量,使用关键字union来定义

共用体(有些人也叫"联合")声明和共用体变量定义与结构体十分相似。其形式为:

union 共用体名{

数据类型 成员名;

数据类型 成员名;

...

} 变量名;

共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。

结构体(struct)中所有变量是"共存"的------优点是"有容乃大",全面;缺点是struct内存空间的分配是粗放的,不管用不用,全分配。

而联合体(union)中是各变量是"互斥"的------缺点就是不够"包容";但优点是内存使用更为精细灵活,也节省了内存空间。

示例: typedef struct Person {

char name[20];

char sex;

float height;

int age;

}Per; 这种写法在声明结构体变量的时候就可以用 Per xiaoming;

如果没有typedef 就必须用 struct Person,这里的Per实际上就是 struct Person的别名

/* IO definitions define access restrictions to peripheral registers*/

#ifdef __cplusplus

#define __I volatile /*!< defines 'read only' permissions */

#else

#define __I volatile const /*!< defines 'read only' permissions */

#endif

#define __O volatile /*!< defines 'write only' permissions */

#define __IO volatile /*!< defines 'read / write' permissions */

相关推荐
小辉懂编程28 分钟前
C语言:51单片机实现数码管依次循环显示【1~F】课堂练习
c语言·开发语言·51单片机
醍醐三叶1 小时前
C++类与对象--2 对象的初始化和清理
开发语言·c++
Magnum Lehar2 小时前
3d游戏引擎EngineTest的系统实现3
java·开发语言·游戏引擎
Mcworld8573 小时前
java集合
java·开发语言·windows
成功人chen某3 小时前
配置VScodePython环境Python was not found;
开发语言·python
wuqingshun3141593 小时前
蓝桥杯 16. 外卖店优先级
c++·算法·职场和发展·蓝桥杯·深度优先
逼子格3 小时前
硬件工程师笔记——二极管Multisim电路仿真实验汇总
笔记·嵌入式硬件·硬件工程师·multisim·硬件工程师学习·电子器件·电路图
「QT(C++)开发工程师」4 小时前
STM32 | FreeRTOS 递归信号量
python·stm32·嵌入式硬件
海绵宝宝贾克斯儿4 小时前
C++中如何实现一个单例模式?
开发语言·c++·单例模式
史迪仔01124 小时前
[python] Python单例模式:__new__与线程安全解析
开发语言·python·单例模式