本帖最后由 jobszheng5 于 2024-2-23 21:03 编辑
# [NUCLEO-C031C6]Keil环境搭建,LED状态灯与调试信息输出
nucleo-c031开发板已经拿到手了!现在就开始上手玩呗!
我们先把我们软件开发环境Keil搭建完成。将代码源文件按功能模块划分为以下几个文件夹,选择ST公司的STM32C031C6型号,在标签页debug选择st-link。之后,可以看到Keil可以通过ST-Link成功找到C031的芯片。
为了验证我们的Keil开发环境和调试器,我们编写功能代码依次实现下述功能:
## 外置48MHz晶振
nucleo-c031开发板外置了一颗48MHz晶振,我们使用其为MCU提供时钟源,即系统默认主频为48MHz。为了验证我们正确开启时钟,我们将sysclk分频四分之一后,通过MCO2引脚(PB2)引出时钟,预期值为12MHz。通过示波器观看输出波形:
## LED翻转
主时钟初始化完成之后,我们将配置系统节拍定时器systick,通过其产生1ms的时基,供程序打点计时使用。每计数500ms后,将LED灯输出结果翻转。输出结果如下图所示:
## 调度信息输出
通过原理图,可以看到,ST-Link虚拟出来的串口与C031芯片的usart2外设相连。我们也将其做为调度信息输出串口,将调度过程中的各类信息通过此外设打印到我们的串口终端之上。
usart2外设的实现方式我本次采用DMA发送的方式。串口初始化的核心代码如下:
```c
static void usart2_init(void)
{
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* DMA interrupt init */
/* DMA1_Channel2_3_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART2 DMA Init */
/* USART2_TX Init */
/* USART2_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART2_TX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* USART2 interrupt Init */
NVIC_SetPriority(USART2_IRQn, 0);
NVIC_EnableIRQ(USART2_IRQn);
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
USART_InitStruct.BaudRate = 115200;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART2, &USART_InitStruct);
LL_USART_ConfigAsyncMode(USART2);
/* USER CODE BEGIN WKUPType USART2 */
/* USER CODE END WKUPType USART2 */
LL_USART_Enable(USART2);
/* Polling USART2 initialisation */
while((!(LL_USART_IsActiveFlag_TEACK(USART2))) || (!(LL_USART_IsActiveFlag_REACK(USART2))))
{
}
}
static void uart_dma_send(char *buf, uint8_t len)
{
while (jlog_status != uart_tx_idle)
{
;
}
LL_USART_EnableDMAReq_TX(USART2);
jlog_status = uart_tx_busy;
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, len);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
}
void jlog_init(void)
{
jlog_status = uart_tx_idle;
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)jlog_buf);
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t) & (USART2->TDR));
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
}
int main(void)
{
jlog_init();
while (1)
{
if (timeline_ms > 500)
{
timeline_ms = 0;
led_toggle();
jlog_printf("Hello eeworld! Hello STM32C031!\r\n");
}
}
}
```
我们通过周期性的输出调度信息来验证我们串口打印的正确性。
本次实验的视频:
STM32C031环境验证