1.001 CortexM温习-起步Demo

STM32 DMA使用详解

1、画图Cortex-M3内部结构图,要体现相应的总线,并标注其作用。

Icode:程序存在Flash中,通过ICode(Instruction Code)总线与Cortex连接取指令。

Dcode:数据被存放在外设内部Flash(SRAM)中,通过DCode(Data Code)访问。

Systembus: 访问外设的寄存器,通常说的寄存器编程就是用这条总线的。

DMA: 数据变量拷贝时可以不占用CPU,通过DMA(Direct Memory Access)总线和DMA1、DMA2完成。

2、关于RCC时钟,完成如下任务

(1)画出RCC时钟树简图,要体现出相关的时钟源

整个系统有四个部分需要时钟

USB

各种外设

RTC

看门狗

前两种主要是靠内部或外部高速时钟,默认复位后是内部高数时钟

RTC通过RTCsel来从HSE、LSE、LSI中选择一个

看门狗就是内部低速时钟

PLL准确的的来说并不是一个时钟,它是将时钟源传过来的时钟信号倍频再传给后续的外设

整个时钟树里有四个选择开关:

1.PLLXTPRE 倍频前分频选择开关,在传给PLLMUTL倍频前要不要分频

2.PLLSRC 倍频前输入信号来源选择开关,是选择内部的还是外部的

3.SW 各种外设时钟源选择开关,可以选择内部的还是外部的还是PLL倍频后 上面PLL倍频后的有内部倍频后的还是外部直接倍频 后的还是外部分频再倍频后的 所以SW切换后的有5种不同路径的时钟源个各种外设

4.RTCsel RTC时钟源选择开关,可以切换三种来源,一高速外部时钟128分频后,二外部低速,三内部低速

复位后默认的都是内部高速和内部低速时钟源,倍频也没有打开

(2)简述由8M晶振到72M主频的过程,以及通过寄存器方式配置72M主频的过程

要达到72MHz ,那就必须要开倍频,且必须使用外部高速时钟,内部高速时钟在倍频前有一个2分频所以最高只能倍频到64MHz

以外部晶振为8MHz来说,路径是,

PLLXTPRE不分频-> PLLSRC选外部高速 -> PLLMULT 设为9倍频 -> SW切换为PLL输入

上述路径可以使系统主频达到72MHz

以下是整个的配置过程

RCC_CR 地址:0x40021000 + 0 = 0x40021000 复位值:0x00000083 16位HSEON置一,然后判断17位HSERDY,外部时钟就绪后进性下一步

RCC_CFGR 地址:0x40021000 + 0x04 = 0x40021004 复位值:0x00000000 就是我们上边说的哪个顺序,16位PLLSRC置1,17位PLLXTPRE置0 ,然后18-21位的PLLMUL

置0111,4-7位AHB预分频置0000不分频,8-10位APB1预分频置100,2分频(因为ahb是72mhz,apb1最高可以36mhz,所以必须分频)。11-13位APB2预分频置000,不分频。

RCC_CR 24位PLLON置一,判断25位PLLRDY,为1说明就绪,继续下一步。

RCC_CFGR 0-1位SW置10,PLL输出作为系统时钟,然后判断2-3位,是否为10(PLL输出作为系统时钟)

STM32配置时钟为72mhz

STM32系统时钟设置详解

(3)阅读如下代码,理解并解释每一步的作用

typedef unsigned short int uint16_t;  //定义一个short型变量占两个字节长度
typedef unsigned       int uint32_t;  //定义一个int型变零占四个字节长度
#define   _IO  volatile
#define PERIPH_BASE      ((uint32_t)0x40000000)  //定义外设的基地址
#define APB2PPERIPH_BASE  (PERIPH_BASE + 0x10000)//定义外设总线APB2的基地址
#define GPIOC_BASE       (APB2PPERIPH_BASE + 0x1000)//定义外设总线APB2上挂载的GPIOC基地址
#define GPIOC            (GPIOC_BASE)//定义GPIOC引脚的基地址
#define GPIOC_CRH        (GPIOC + 0x04) //定义GPIOC端口配置高寄存器
#define GPIOC_ODH        (GPIOC + 0x0c)//定义端口数据输出寄存器
#define AHBPERIPH_BASE  (PERIPH_BASE + 0x20000)//定义高速总线AHB的基地址
#define RCC_BASE         (AHBPERIPH_BASE + 0x1000)//定义RCC时钟基地址
#define RCC              (RCC_BASE) //定义RCC时钟基地址
#define RCC_APB2ENR      (RCC + 0x18) //定义使能挂载在APB2上的外设的寄存器
#define RCC_CR           (RCC + 0x00)//定义时钟控制寄存器
#define RCC_CFGR         (RCC + 0x04)//定义时钟配置寄存器
#define FLASH_R_BASE     (AHBPERIPH_BASE + 0x2000)  //定义AHB上挂载的flash接口地址
#define FLASH            (FLASH_R_BASE ) 
#define FLASH_ACR        (FLASH + 0x00)
void RCC_init(uint16_t PLL)  //传入倍频数PLL
{
    uint32_t temp = 0;
    *((uint32_t *)RCC_CR) |= 0x00010000;//将HSEON位置1
    while (!(*((uint32_t*)RCC_CR) >> 17)); //等待HSERDY位硬件置1后跳出循环
    *((uint32_t *)RCC_CFGR) = 0X00000400; //将PPRE1位置100,,将HCLOCK二分频为PCLOCK1
    PLL -= 2;     //PLLMUL位是从0000开始二倍频,所以要将传入的倍频数减去一个2等于PLLMUL位实际应该写入的真实值
    *((uint32_t *)RCC_CFGR) |= PLL << 18;  //将倍频位置为需要的倍频
    *((uint32_t *)RCC_CFGR) |= 1 << 16;   //将PLLSRC位置1,选择HSE为倍频输入时钟源
    *((uint32_t *)FLASH_ACR) |= 0x2;      //将LATENCY位置为010,两个等待状态,闪存读取要和时钟频率一致不然程序会跑飞
    *((uint32_t *)RCC_CR) |= 0x01000000;  //将PLLON位置1,开启PLL倍频
    while (!(*((uint32_t*)RCC_CR) >> 25)); //等待PLLRDY位硬件置1后跳出循环
    *((uint32_t *)RCC_CFGR) |= 0x00000002; //将SW位置1,选择倍频后的时钟源作为系统时钟源
    while (temp !=0x02)                   //等待SWS位硬件置为10时,PLL成功作为系统时钟源输出
    {
        temp = *((uint32_t *)RCC_CFGR) >> 2; //将SWS的两位移到最右边
        temp &= 0x03;                       //与11取与
    }
    
}

3.flash寄存器设置延时周期的作用

STM32配置时钟时注意设置FLASH等待周期

4.通过寄存器点亮led

typedef  unsigned int  u32;
#define GPIOC_BASE0x40011000
#define PERIPH_BASE0x40000000
#define APB2_BASE(PERIPH_BASE+0x10000)
#define AHB_BASE(PERIPH_BASE+0x20000)
#define RCC_BASE(AHB_BASE+0x1000)
#define RCC_APB2ENR(RCC_BASE+0x18)
#define GPIOx_CRH_OFF0x0004
#define GPIOx_ODR_OFF0x000C
#define GPIOx_CRH  (GPIOC_BASE+GPIOx_CRH_OFF)//0x4001 1004
#define GPIOx_ODR(GPIOC_BASE+GPIOx_ODR_OFF)//0x4001 100C
void delay(u32 x)
{
u32 i = 0;
while(x--)
{
i = 10000000;
while(i--);
}
}
int main(void)
{
*((unsigned int *)RCC_APB2ENR) |= 0x00000010;
//*((unsigned int *)GPIOx_CRH) = 0x00300000;//error
//先清除寄存器相应位的值
*((unsigned int *)GPIOx_CRH) &= 0xff0fffff;
//然后再进行对相应位赋值
*((unsigned int *)GPIOx_CRH) |= 0x00300000;
//*((unsigned int *)GPIOx_CRH) =  *((unsigned int *)GPIOx_CRH)  +  0x00300000;
//*(GPIOx_CRH) = 0x00300000;
*((unsigned int *)GPIOx_ODR) &= ~(1<<13);
*((unsigned int *)GPIOx_ODR) |= 0x00000000;
//闪烁 
while(1)
{
//亮
*((unsigned int *)GPIOx_ODR) &= ~(1<<13);
*((unsigned int *)GPIOx_ODR) |= 0x00000000;
//延时一些时间
//sleep(2);
delay(1);
//循环
//灭
*((unsigned int *)GPIOx_ODR) &= ~(1<<13);
*((unsigned int *)GPIOx_ODR) |= 0x00002000;//0000 0000 0000 0000 0010 0000 0000 0000 
//延时一些时间
delay(1);
}
return 0;
}

上面一种是直接对ODR寄存器输出高低电平来控制亮灭

下面这种是通过BSRR寄存器来控制输出高低电平来控制亮灭

/*******************************************************************************
--------------------------------------------------------------------------------
* 实 验 名 : 使用寄存器点亮一个LED
* 实验说明       : 操作寄存器控制LED1指示灯闪烁
* 连接方式       : 
* 注    意 : 
*******************************************************************************/
#include "stm32f10x.h"
typedef unsigned int u32;   //类型重定义 unsigned int -- u32
void SystemInit()
{
}
/*******************************************************************************
* 函 数 名         : delay
* 函数功能   : 延时函数,通过while循环占用CPU,达到延时功能
* 输    入         : i
* 输    出         : 无
*******************************************************************************/
void delay(u32 i)
{
while(i--);
}
/*******************************************************************************
* 函 数 名         : main
* 函数功能   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
RCC_APB2ENR |= 1<<4;
GPIOC_CRH &= ~( 0x0F<< (4*5));//将MODE13和CONF13四位清零
GPIOC_CRH |= (1<<4*5);        //将MODE13和CONF13四位置为0100
GPIOC_ODR &=~(1<<13);//配置输出低电平
GPIOC_BSRR=(1<<(16+13));
while(1)
{
GPIOC_BSRR=(1<<(16+13));
delay(0x1FFFFF);
GPIOC_BSRR=(1<<(13));
delay(0x1FFFFF);
}
}

————————————————

版权声明:本文为CSDN博主「GK小卜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_42224577/article/details/114745801

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值