打印
[其他ST产品]

stm32中DMA,时钟树、内存总线、配置时钟时先配置flash->acr、通过寄存器点亮led

[复制链接]
楼主: wang6623
手机看帖
扫描二维码
随时随地手机跟帖
21
wang6623|  楼主 | 2023-9-25 18:08 | 只看该作者 |只看大图 回帖奖励 |倒序浏览

上图中的外部时钟源指的是相对于core的内部,但还是在stm32芯片上

使用特权

评论回复
22
wang6623|  楼主 | 2023-9-25 18:08 | 只看该作者
内核时钟数值上等于HCLK时钟,可以通过设置HCLK时钟来决定FCLK时钟的大小

参考:《Cortex-M3 权威指南》

使用特权

评论回复
23
wang6623|  楼主 | 2023-9-25 18:09 | 只看该作者
]

使用特权

评论回复
24
wang6623|  楼主 | 2023-9-25 18:09 | 只看该作者
整个系统有四个部分需要时钟

USB
各种外设
RTC
看门狗
前两种主要是靠内部或外部高速时钟,默认复位后是内部高数时钟
RTC通过RTCsel来从HSE、LSE、LSI中选择一个
看门狗就是内部低速时钟

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

使用特权

评论回复
25
wang6623|  楼主 | 2023-9-25 18:09 | 只看该作者
整个时钟树里有四个选择开关:

1.PLLXTPRE 倍频前分频选择开关,在传给PLLMUTL倍频前要不要分频
2.PLLSRC 倍频前输入信号来源选择开关,是选择内部的还是外部的
3.SW 各种外设时钟源选择开关,可以选择内部的还是外部的还是PLL倍频后 上面PLL倍频后的有内部倍频后的还是外部直接倍频 后的还是外部分频再倍频后的 所以SW切换后的有5种不同路径的时钟源个各种外设

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

使用特权

评论回复
26
wang6623|  楼主 | 2023-9-25 18:09 | 只看该作者
复位后默认的都是内部高速和内部低速时钟源,倍频也没有打开

使用特权

评论回复
27
wang6623|  楼主 | 2023-9-25 18:12 | 只看该作者
(2)简述由8M晶振到72M主频的过程,以及通过寄存器方式配置72M主频的过程
要达到72MHz ,那就必须要开倍频,且必须使用外部高速时钟,内部高速时钟在倍频前有一个2分频所以最高只能倍频到64MHz

以外部晶振为8MHz来说,路径是,
PLLXTPRE不分频-> PLLSRC选外部高速 -> PLLMULT 设为9倍频 -> SW切换为PLL输入

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

使用特权

评论回复
28
wang6623|  楼主 | 2023-9-25 18:12 | 只看该作者
以下是整个的配置过程

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输出作为系统时钟)

使用特权

评论回复
29
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
(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取与
    }
   
}

使用特权

评论回复
30
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
3.flash寄存器设置延时周期的作用
STM32配置时钟时注意设置FLASH等待周期

使用特权

评论回复
31
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
4.通过寄存器点亮led
typedef  unsigned int  u32;

#define GPIOC_BASE                        0x40011000
#define PERIPH_BASE                        0x40000000
#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_OFF                0x0004
#define GPIOx_ODR_OFF                0x000C
#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;
}

使用特权

评论回复
32
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
上面一种是直接对ODR寄存器输出高低电平来控制亮灭

使用特权

评论回复
33
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
下面这种是通过BSRR寄存器来控制输出高低电平来控制亮灭

使用特权

评论回复
34
wang6623|  楼主 | 2023-9-25 18:13 | 只看该作者
/*******************************************************************************
*                 
*                                        普中科技
--------------------------------------------------------------------------------
* 实 验 名                 : 使用寄存器点亮一个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);
        }
}




使用特权

评论回复
35
Pulitzer| | 2024-2-21 07:06 | 只看该作者

通过访问寄存器来控制I2C1工作时钟的开启。

使用特权

评论回复
36
童雨竹| | 2024-2-21 09:02 | 只看该作者

这种方法可以使散热体积和表面面积增大两倍多

使用特权

评论回复
37
Wordsworth| | 2024-2-21 10:05 | 只看该作者

I2C1工作时钟源选择;I2C1模块工作时钟的开启使能。

使用特权

评论回复
38
Clyde011| | 2024-2-21 11:08 | 只看该作者

STM32芯片中有多个工作时钟源的外设很常见

使用特权

评论回复
39
公羊子丹| | 2024-2-21 12:01 | 只看该作者

功率开关漏极(或集电极)

使用特权

评论回复
40
万图| | 2024-2-21 13:04 | 只看该作者

CPU借助于APB总线访问相关寄存器达到对I2C1工作模块的控制

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则