完成时钟初始化后,接下来就可以对各总线下的外设进行配置,并实现其相关驱动接口功能。接下来我们以串口为例来进行外设初始化流程。
一、确认串口时钟源
在我的开发板上,使用usart1作为调试串口使用,所以需要用到PA9与PA10两个gpio管脚。如下图所示:
同时usart1串口使用的时钟源为PCLK2(也就是APB2),其时钟配置如下代码所示:
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)0x00;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)0x00;
/* PCLK1 = HCLK / 2 */
RCC->CFGR0 |= (uint32_t)0x400;
SYSCLK == HCLK == PCLK2 == PCLK1 * 2
如上就是系统时钟的配置关系,所以可知usart1串口的时钟源频率为96MHz。
其时钟树路径如下图所示:
二、初始化串口
确认好串口的时钟源后,接下来就可以使能usart1对应的总线时钟,以及配置usart1的波特率等设置。
初始化串口代码如下所示:
/*********************************************************************
* @fn usart1_init
*
* @brief 初始化usart1串口,并默认配置其波特率为115200.
*
* @param none
*
* @return none
*/
void usart1_init(void)
{
uint32_t div = 0;
// 使能usart1时钟和GPIOA的时钟
RCC->APB2PCENR |= USART1EN | IOPAEN;
// 配置PA9引脚为功能复用输出,PA10为带上拉输入
GPIOA->CFGHR |= 0x000008B0;
GPIOA->OUTDR |= 0x00000400;
// 默认配置usart1的波特率为115200
div = (PCLK2 / 16) / 115200;
USART1->BRR = (div << 4) + 1;
// 使能usart1的发送器
USART1->CTLR1 |= CTRL1_TE;
// 使能usart1的串口
USART1->CTLR1 |= CTRL1_UE;
}
- 首先使能usart1与gpio_a的时钟,使能了它们的时钟才能使对应的外设正常工作;
- 配置PA9与PA10引脚的复用模式,对于PA9应该配置为复用输出,P10应该配置为上拉输入;
- 然后再设置usart1的波特率、数据位长度、奇偶校验以及停止位,这里默认设置为:115200,8,none,1;
- 最后再打开usart1的发送器,以及usart1串口总使能。
三、实现串口输出接口
此时就可以通过串口数据寄存器来进行操作串口的输出了,代码如下所示:
/*********************************************************************
* @fn usart1_put
*
* @brief 使用usart1串口输出单个字符.
*
* @param c,需要输出的字符数据.
*
* @return none
*/
void usart1_put(uint8_t c)
{
uint16_t data = c & 0xff;
// 检测发送状态,等待发送完毕
while((USART1->STATR & STATUS_TC) == 0);
// 填入待发送数据
USART1->DATAR = data;
}
/*********************************************************************
* @fn usart1_puts
*
* @brief 使用usart1串口输出字符串.
*
* @param c,需要输出的字符串指针.
*
* @return 返回总共发送的字符个数
*/
int usart1_puts(char *c)
{
int cnt = 0;
// 检测是否到字符串的结尾,如果到了字符串结尾,则退出循环
while(*c)
{
// 进行单个字符数据的发送
usart1_put((uint8_t)*c);
// 对发送数据个数进行计数
cnt++;
c++;
}
return cnt;
}
在代码中通过调用usart1_puts函数即可进行字符串的输出打印。
四、实现效果
在start_kernel函数中进行打印输出,相关代码与输出打印如下所示:
void start_kernel(void)
{
// 设置sysclk系统时钟为96MHz
clock_hse_96Mhz();
// 设置usart1,并初始化配置为115200,8,none,1
usart1_init();
usart1_puts("hello RVOS!\r\n");
usart1_puts("\r\n======== RVOS ========\r\n");
led2_ctrl(1);
while (1) {} // stop here!
}