第三篇---STM32灵魂塑造之呱呱坠地

      之前我从宏观上介绍了CM3架构和STM32的相关内容,现在我们就开始正式进行STM32的灵魂塑造---程序编写。为什么说是塑造,因为整个代码是从无到有的而非利用官方库的开发,就好像新生的婴儿呱呱坠地。。。罗嗦止于此,切入正题!

      在我的一篇文章《ARM寄存器C操作探讨》里,我曾详细的介绍了ARM通常采用的两种寄存器C操作的方式,现在我们就实际应用一下第二种方法。为了帮初学者形成ARM编程的一般思路和思想,我会从解读Datasheet到实际编程都说明的非常详细。

      首先,我们要读Datasheet,这里我选用的芯片是STM32F103RB,大家可以到ST的官网寻找下载,读Datasheet读什么?就像物质是由原子组成,程序是由寄存器的配置组成,尤其对ARM来说,灵活的配置寄存器是基础中的基础,说来容易,可至此还是有种无从下手的感觉,下面我就从寄存器操作开始讲讲构建自己的ARM编程模式。

      打开KEIL,新建一个工程,device选择STM32F103RB,详细的我这里不再展开,相信大家在51或其它微处理器的学习中都用的熟的不能再熟,不赘述,直奔核心---寄存器的操作。要操作一个寄存器我们得知道这个寄存器的地址,如何寻址?这就是重点。我们需要查看Datasheet来确定STM32F103RB这个芯片或者说STM32F103系列芯片的寄存器映射。依据这个内存映射,我们可以找到芯片外设的首地址,而这正是我们想要的、需要的。那么具体怎么写?我们新建一个名为MYstm32f10x_map.h的文件,内容可以这么写:

     

#ifndef MYstm32f10x_map_h_h_
#define MYstm32f10x_map_h_h_

//数据类型定义
typedef unsigned int  uint32;
typedef unsigned short int uint16;

//####################################################################################
//****RCC REGS******//
//####################################################################################

typedef struct tagRCC_REGS{
	uint32 CR;       //时钟控制寄存器
	uint32 CFGR;     //时钟配置寄存器
	uint32 CIR;      //时钟中断寄存器
	uint32 APB2RSTR; //APB2外设复位寄存器
	uint32 APB1RSTR; //APB1外设复位寄存器
	uint32 AHBENR;   //AHB外设时钟使能寄存器
	uint32 APB2ENR;  //APB2外设时钟使能寄存器
	uint32 APB1ENR;  //APB1外设时钟使能寄存器
	uint32 BDCR;     //备份域控制寄存器
	uint32 CSR;      //控制/状态寄存器
}RCC_REGS;

#define RCC ((volatile RCC_REGS *)0x40021000)    //RCC寄存器组首地址

//####################################################################################
//****GPIO REGS****//
//####################################################################################

typedef struct tagGPI0X_REGS{	 //X=A\B\C
	uint32 CRL;  //端口配置低寄存器
	uint32 CRH;  //端口配置高寄存器
	uint32 IDR;  //端口输入数据寄存器
	uint32 ODR;  //端口输出数据寄存器
	uint32 BSRR; //端口位设置/清除寄存器
	uint32 BRR;  //端口位清除寄存器
	uint32 LCKR; //端口配置锁定寄存器
}GPIOX_REGS;

#define GPIOA ((volatile GPIOX_REGS *)0x40010800)	 //端口A寄存器组首地址
#define GPIOB ((volatile GPIOX_REGS *)0x40010C00)	 //端口B寄存器组首地址
#define GPIOC ((volatile GPIOX_REGS *)0x40011000)	 //端口C寄存器组首地址

//####################################################################################
//*****TIME REGS******//
//####################################################################################

typedef struct tagADVANCED_TIMX_REGS{		  //高级控制定时器(X)寄存器组
	uint32 CR1;      //控制寄存器1
	uint32 CR2;      //控制寄存器2
	uint32 SMCR;     //从模式控制寄存器
	uint32 DIER;     //中断使能寄存器
	uint32 SR;       //状态寄存器
	uint32 EGR;      //事件产生寄存器
	uint32 CCMR1;    //捕获/比较模式寄存器1
	uint32 CCMR2;    //捕获/比较模式寄存器2
	uint32 CCER;     //捕获/比较使能寄存器
	uint32 CNT;      //计数器
	uint32 PSC;      //预分频器
	uint32 ARR;      //自动装载寄存器
	uint32 RCR;      //重复计数寄存器
	uint32 CCR1;     //捕获/比较寄存器1
	uint32 CCR2;     //捕获/比较寄存器2
	uint32 CCR3;     //捕获/比较寄存器3
	uint32 CCR4;     //捕获/比较寄存器4
	uint32 BDTR;     //刹车和死区寄存器
	uint32 DCR;      //DMA控制寄存器
	uint32 DMAR;     //连续模式的DMA地址
}ADVANCED_TIMX_REGS;

typedef struct tagGENERAL_TIMX_REGS{		  //X=2-4
	uint32 CR1;      //控制寄存器1
	uint32 CR2;      //控制寄存器2
	uint32 SMCR;     //从模式控制寄存器
	uint32 DIER;     //DMA/中断使能寄存器
	uint32 SR;       //状态寄存器
	uint32 EGR;      //事件产生寄存器
	uint32 CCMR1;    //捕获/比较模式寄存器1
	uint32 CCMR2;    //捕获/比较模式寄存器2
	uint32 CCER;     //捕获/比较使能寄存器
	uint32 CNT;      //计数器
	uint32 PSC;      //预分频器
	uint32 ARR;      //自动装载寄存器
	uint32 CCR1;     //捕获/比较寄存器1
	uint32 CCR2;     //捕获/比较寄存器2
	uint32 CCR3;     //捕获/比较寄存器3
	uint32 CCR4;     //捕获/比较寄存器4
	uint32 DCR;      //DMA控制寄存器
	uint32 DMAR;     //连续模式的DMA地址
}GENERAL_TIMX_REGS;

#define TIM1 ((volatile ADVANCED_TIMX_REGS *) 0x40012C00) //高级控制定时器1寄存器组首地址
#define TIM2 ((volatile GENERAL_TIMX_REGS *) 0x40000000)  //通用控制定时器2寄存器组首地址
#define TIM3 ((volatile GENERAL_TIMX_REGS *) 0x40000400)  //通用控制定时器3寄存器组首地址
#define TIM4 ((volatile GENERAL_TIMX_REGS *) 0x40000800)  //通用控制定时器4寄存器组首地址

//####################################################################################
//*****ADC REGS******//
//####################################################################################

typedef struct tagADCX_REGS{
	uint32 SR;      //ADC状态寄存器
	uint32 CR1;     //ADC控制寄存器1
	uint32 CR2;     //ADC控制寄存器2
	uint32 SMPR1;   //ADC采样时间寄存器1
	uint32 SMPR2;   //ADC采样时间寄存器2
	uint32 JOFR1;   //ADC注入通道数据偏移寄存器1
	uint32 JOFR2;   //ADC注入通道数据偏移寄存器2
	uint32 JOFR3;   //ADC注入通道数据偏移寄存器3
	uint32 JOFR4;   //ADC注入通道数据偏移寄存器4
	uint32 HTR;     //ADC看门狗高阀值寄存器
	uint32 LTR;     //ADC看门狗低阀值寄存器
	uint32 SQR1;    //ADC规则序列寄存器1
	uint32 SQR2;    //ADC规则序列寄存器2
	uint32 SQR3;    //ADC规则序列寄存器3
	uint32 JSQR;    //ADC注入序列寄存器
	uint32 JDR1;    //ADC 注入数据寄存器1
	uint32 JDR2;    //ADC 注入数据寄存器2
	uint32 JDR3;    //ADC 注入数据寄存器3
	uint32 JDR4;    //ADC 注入数据寄存器4
	uint32 DR;      //ADC规则数据寄存器	
}ADCX_REGS;

#define ADC1 ((volatile ADCX_REGS *) 0x40012400)	//ADC1寄存器组首地址
#define ADC2 ((volatile ADCX_REGS *) 0x40012800)	//ADC2寄存器组首地址


//等等。。。。。。


#endif

     

       如上,然后我们就可以在.c文件里包含这个头文件,并根据技术手册里的各外设的寄存器描述来读写相应的寄存器,完成想要实现的功能。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

注意:

        可能你在编译过程中会报错,大体意思是说你没有定义某结构体,可我们明明定义了,我想这可能是KEIL的一个BUG(当然也有可能是盗版的缘故~),经过几次猜想验证之后,我发现在typedef struct...这个结构体定义时,在最后的结构体名一定要是你一个字一个字敲进去的,而不是从tagXXX中拷贝而来的,如果是从tagXXX拷贝而来的话就会报上述的错误(真是什么奇怪的事都可能存在~)。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

     欢迎大家扫描下方二维码关注我的个人微信公众号,一起交流学习,谢谢。

      

     

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章