不支持位带操作
只有一条AHB-lite总线接口连到存储器、总线矩阵等
1条外设总线,APB速度高达48MHz
4个中断优先级
GPIO连载AHB总线,最高翻转速度为12MHz一、时钟系统
M0芯片的时钟源有4个,
一个高速内部RC时钟源,频率为8M,精度1%
一个高速外部时钟源,频率为8到32MHz
一个低速外部时钟源,频率一般为32.768kHz,驱动RTC
一个低速内部时钟源,频率为40kHz,驱动IWDG
芯片上电的时候默认启用内部RC震荡,即8MHz的内部时钟源
倍频最高48MHz
启用HSI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /* ********************************************************************************************************* * 函 数 名: HSI_setSysClk * 功能说明: 设置HSI为系统时钟, * 形 参: * 返 回 值: 无 ********************************************************************************************************* */ void HSI_setSysClk( void ) { __IO uint32_t StartUpCounter = 0, HSIStatus = 0; /* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/ /* Enable HSI*/ //使能内部时钟 RCC->CR |= ((uint32_t)RCC_CR_HSION); //使用内部8M时钟 /* Wait till HSI is ready and if Time out is reached exit */ //等待内部时钟起振 do { HSIStatus = RCC->CR & RCC_CR_HSIRDY; StartUpCounter++; } while ((HSIStatus== 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSIRDY) != RESET) //使用内部8M时钟 { HSIStatus = (uint32_t)0x01; } else { HSIStatus = (uint32_t)0x00; } if (HSIStatus == (uint32_t)0x01) { /* Enable Prefetch Buffer and set Flash Latency */ //flash总线时钟使能 FLASH->ACR |= FLASH_ACR_PRFTBE; FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY; /* HCLK = SYSCLK */ //外设AHB总线时钟等于系统时钟 RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK = HCLK */ //外设APB总线时钟等于系统时钟 RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1; /* PLL configuration = HSI/2 * 12= 48 MHz */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL12); //RC时钟2分频后 进行12倍频 /* Enable PLL */ //使能锁相环倍频开关 RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ //等待锁相环就绪 while ((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Select PLL as system clock source */ //选择锁相环输出时钟作为系统时钟 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* Wait till PLL is used as system clock source */ //等待锁相环输出时钟已经成为系统时钟 while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) { } } else { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ } } |
二、NVIC
4个中断优先级1 2 3 | /* 开关全局中断的宏 */ #define ENABLE_INT() __enable_irq() /* 使能全局中断 */ #define DISABLE_INT() __disable_irq() /* 禁止全局中断 */ |
1 2 3 4 5 6 7 8 9 10 | void NVIC_Configuration( void ) { NVIC_InitTypeDef NVIC_InitStructure; /* 外设中断 */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //IRQ通道:串口1 NVIC_InitStructure.NVIC_IRQChannelPriority = 1; //优先级 :1级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能IRQ通道 NVIC_Init(&NVIC_InitStructure); } |
三、GPIO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #define PORT_LED GPIOC //端口 #define PIN_LED GPIO_Pin_13 //引脚 #define LED_ON (PORT_LED->BSRR = PIN_LED) #define LED_OFF (PORT_LED->BRR = PIN_LED) #define LED_TOGGLE (PORT_LED->ODR ^= PIN_LED) /* ********************************************************************** * @fun :bsp_led_init * @brief :板上LED初始化 * @param :None * @return :None * @remark : ********************************************************************** */ void bsp_led_init( void ) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = PIN_LED; //LED引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //高速输出 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推完输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉(浮空) GPIO_Init(PORT_LED, &GPIO_InitStructure); } |
四、定时器
滴答定时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | /* ********************************************************************** * @fun :SysTick_Init * @brief :滴答定时器初始化,提供1ms时基 * @param :None * @return :=0,初始化成功;=1,初始化失败 * @remark :None ********************************************************************** */ unsigned char SysTick_Init( void ) { unsigned char sysFlag = 1; /* SystemFrequency / 1000 1ms中断一次 * SystemFrequency / 100000 10us中断一次 * SystemFrequency / 1000000 1us中断一次 */ sysFlag = SysTick_Config(SystemCoreClock / 1000); return sysFlag; } /* ********************************************************************** * @fun :bsp_DelayUS * @brief :us级延迟。 必须在systick定时器启动后才能调用此函数 * @param :None * @return :n-延迟长度,单位1 us * @remark :None ********************************************************************** */ void bsp_DelayUS(uint32_t n) { uint32_t ticks; uint32_t told; uint32_t tnow; uint32_t tcnt = 0; uint32_t reload; reload = SysTick->LOAD; ticks = n * (SystemCoreClock / 1000000); /* 需要的节拍数 */ tcnt = 0; told = SysTick->VAL; /* 刚进入时的计数器值 */ while (1) { tnow = SysTick->VAL; if (tnow != told) { /* SYSTICK是一个递减的计数器 */ if (tnow < told) { tcnt += told - tnow; } /* 重新装载递减 */ else { tcnt += reload - tnow + told; } told = tnow; /* 时间超过/等于要延迟的时间,则退出 */ if (tcnt >= ticks) { break ; } } } } /* ********************************************************************** * @fun :SysTick_Handler * @brief :滴答定时器中断服务函数 * @param :None * @return :=0,初始化成功;=1,初始化失败 * @remark :None ********************************************************************** */ void SysTick_Handler( void ) { } |
五、串口
重定向prinf函数1、需要在Options for Target -> Code Generation 中勾选Use MicroLIB;
2、需要加入下面这个函数:
int fputc(int ch, FILE *f)
{
USART_SendData(USART1,(uint8_t)ch);
while (USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
return (ch);
}
3、需要加入如下一个头文件:
#include "stdio.h"
(在网上看到多数人加了两个头文件:
#include "stdio.h"
#include "stdarg.h"
但在实际中只需加入一个头文件即可
)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar( int ch) #else #define PUTCHAR_PROTOTYPE int fputc ( int ch, FILE *f) #endif /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1, (uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) { } return ch; } |
六、看门狗
驱动独立看门狗的晶振为40KHz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /* ********************************************************************** * @fun :bsp_iwdg_init * @brief :独立看门狗初始化,超时时间2048ms * @param :None * @return :None * @remark : ********************************************************************** */ void bsp_iwdg_init( void ) { if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) RCC_ClearFlag(); //清除标志 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能寄存器 写功能 IWDG_SetPrescaler(IWDG_Prescaler_64); //设置预分频 40K/64=0.625k 一个周期是 1.6ms IWDG_SetReload(1280); //1280*1.6ms=2048ms //设置初值 IWDG_ReloadCounter(); //喂狗 IWDG_Enable(); //使能独立看门狗 } /* ********************************************************************** * @fun :bsp_iwdg_feed * @brief :独立看门狗喂狗,必须在超时时间内调用 * @param :None * @return :None * @remark : ********************************************************************** */ void bsp_iwdg_feed( void ) { IWDG_ReloadCounter(); } |