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