不支持位带操作
只有一条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();} |