欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

AMR开发学习底层库函数寄存器

程序员文章站 2022-06-23 14:35:42
STM32F103最小系统实现智能控制(寄存器实现)一、硬件准备1、学习前准备:整个项目使用C语言开发,所以,需要有良好的C语言基础,这里我就简单说明一下,C语言中,通用链表,函数指针,文件分类,这三点做好,在开发过程中会轻松很多。2、硬件准备:网上购置stm32f103ze学习版,带有电阻屏的(电容屏贵,没钱),还有代码烧写器(jlink),还有语音解码模块,SD卡,DHT11,MP3播放模块,硬件连接图如下3、软件准备:keil 4二、实现功能1、实现功能:时钟,贪吃蛇,音乐播放器,温湿度...

STM32F103最小系统实现智能控制(寄存器实现)

一、硬件准备

1、学习前准备:整个项目使用C语言开发,所以,需要有良好的C语言基础,这里我就简单说明一下,C语言中,通用链表,函数指针,文件分类,这三点做好,在开发过程中会轻松很多。
2、硬件准备:网上购置stm32f103ze学习版,带有电阻屏的(电容屏贵,没钱),还有代码烧写器(jlink),还有语音解码模块,SD卡,DHT11,MP3播放模块,硬件连接图如下
AMR开发学习底层库函数寄存器

3、软件准备:keil 4

二、实现功能

1、实现功能:时钟,贪吃蛇,音乐播放器,温湿度动态显示,记事本,LED灯控制(上述只能控制均可用语音控制实现)

关键代码剖析

1、时钟:芯片的最小单位都是寄存器,如何实现定时器,就如何实现时钟,对于时间的显示,只需要计算一个定时器,然后显示数字就好,这里使RTC时钟

void TimeCount_Install(u8 Time_nu,int Count_time,Tm_pHandle PHandle) { switch(Time_nu) { case TIM2_IRQn: case TIM3_IRQn: case TIM4_IRQn: RCC->APB1ENR |= (1<<(Time_nu-28)); RCC->CFGR &= ~(7<<8); //清空 RCC->CFGR |= (4<<8); //2分频 switch(Time_nu) { case TIM2_IRQn: TIM2->ARR = (Count_time-1); //确定重装载寄存器的值 72MHz=7200*10000,1s计数器产生中断 TIM2->PSC = (7200-1); //配置预分频器(TIMx_PSC) TIM2->DIER |= (1<<0); //允许跟新中断 break; case TIM3_IRQn: TIM3->ARR = (Count_time-1); //确定重装载寄存器的值  72MHz=7200*10000,1s产生中断 TIM3->PSC = (7200-1); //配置预分频器(TIMx_PSC) TIM3->DIER |= (1<<0); //允许跟新中断 break; case TIM4_IRQn: TIM4->ARR = (Count_time-1); TIM4->PSC = (7200-1); TIM4->DIER |= (1<<0); break; } break; case TIM5_IRQn: RCC->APB1ENR |= (1<<3); RCC->CFGR &= ~(7<<8); RCC->CFGR |= (4<<8); TIM5->ARR = (Count_time-1); TIM5->PSC = (7200-1); TIM5->DIER |= (1<<0); break; } IRQ_Install(Time_nu,PHandle); TimeCount_ON(Time_nu); //计数器打开,硬定时器 }

需要说明的是,硬定时器和软定时器,通俗来说,我们在做开发的时候,需要用到很多定时器,但是,对于M3系列的芯片来说,条件有限,所以,我们称,原本的定时器为硬定时器,所谓软定时器,就是,在硬定时器中,再次计数 ,假设硬定时器是1秒,则在里面技术时,那么我们就可以得到10秒钟的软定时器,但这里,为了精确,一般硬定时器都是毫秒,微秒级。(个人理解)
2、中断封装
总共有60个外部中断,每一个中断都有一个中断动作函数,所以,我们在使用中断的时候,就可以在对应的中断函数里面自定义(类似于回调)但是,这样显得有些麻烦,我们可以在启动代码里面,将所有的中断动作函数定义为一个,如下:AMR开发学习底层库函数寄存器
我们是如何知道是哪一个中断产生了呢,我们可以通过NVIC寄存器,遍历中断编号,找出对应的中断信号,具体的代码如下:

void IRQ_Desacth() { int i,IRQ_NU; //循环遍历60个中断,找到动作中断编号 for(i=0;i<60;i++) { if(i<I2C1_ER_IRQn) { if((NVIC->IABR[0]>>i)& 1) { IRQ_NU=i; break; } } else if(i>=32) { if((NVIC->IABR[1]>>(i-I2C1_ER_IRQn))& 1) { IRQ_NU=i; break; } } } switch(IRQ_NU) { case EXTI0_IRQn: case EXTI2_IRQn: case EXTI3_IRQn: case EXTI4_IRQn: //?ж???? IRQ_Events[IRQ_NU].irqpHandle(); //中断结束之后,需要重新置1 EXTI->PR |= (1<<(IRQ_NU-6)); //重新置1  NVIC->ICPR[0] |= (1<<IRQ_NU); //中断解挂 break; case TIM2_IRQn: IRQ_Events[IRQ_NU].irqpHandle(); TIM2->SR &= ~(1<<0); //中断结束后,跟新中断标记 NVIC->ICPR[0] |= (1<<IRQ_NU); //中断解挂 break; case TIM3_IRQn: IRQ_Events[IRQ_NU].irqpHandle(); TIM3->SR &= ~(1<<0); NVIC->ICPR[0] |= (1<<IRQ_NU); break; case TIM4_IRQn: IRQ_Events[IRQ_NU].irqpHandle(); TIM4->SR &= ~(1<<0); NVIC->ICPR[0] |= (1<<IRQ_NU); break; case TIM5_IRQn: IRQ_Events[IRQ_NU].irqpHandle(); TIM5->SR &= ~(1<<0); NVIC->ICPR[1] |= (1<<(IRQ_NU-32)); break; case USART1_IRQn: // USART1->SR &= ~(1<<9); IRQ_Events[IRQ_NU].irqpHandle(); NVIC->ICPR[1] |= (1<<(IRQ_NU-32)); break; case RTC_IRQn: RTC->CRL &= ~(1<<0); IRQ_Events[IRQ_NU].irqpHandle(); NVIC->ICPR[1] |= (1<<IRQ_NU); break; case ADC1_IRQn: ADC1->SR &= ~(1<<0); IRQ_Events[IRQ_NU].irqpHandle(); NVIC->ICPR[1] |= (1<<IRQ_NU); break; } }

说明:并不是每一个中断都需要解挂,置1,这个需要看用户手册,对应的中断解释,这里,我对中断时间进行封装,就是前面所说的函数指针,IRQ_Events[IRQ_NU].irqpHandle();这一步,就是在执行中断产生之后,需要做的事。封装了一个结构体。

三、收获与意义

1、收获与意义:总的来说,现在的ARM开发,都是调用库函数,很多时候,我们并不知道他的流程是怎么样的,那个使用起来也是懵懵的,寄存器实现,就是完整的从底层学起,虽然是很麻烦,还需要去看流程图,配置哪些寄存器,但是,这个学懂之后,去使用库函数就会更加明白,那些库函数,内部其实就是这样实现的,所以,有必要学习一下这个,这样也可以自己去封装。

源码下载

1、下载地址:百度网盘:提取码:w0rs

本文地址:https://blog.csdn.net/qq_42411190/article/details/107897002

相关标签: stm32