打印
[其他]

【灵动微电子MM32F5330测评】3.串口通讯+定时器

[复制链接]
613|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
这次来完成这两个题目

UART,即通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地),如果是单向传输可以只用一个引脚,开发板上已经实现了USB转UART的电路,使用引脚是PA9和PA10

使用串口涉及到GPIO复用功能,复用表可以在数据手册中找到

初始化串口,波特率设置为115200,停止位1,无校验,开启接收中断和空闲中断
void uart_init(void)
{
    GPIO_InitTypeDef gpio_cfg;
    NVIC_InitTypeDef nvic_cfg;
    UART_InitTypeDef uart_cfg;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    UART_StructInit(&uart_cfg);
    uart_cfg.BaudRate      = 115200;
    uart_cfg.WordLength    = UART_WordLength_8b;
    uart_cfg.StopBits      = UART_StopBits_1;
    uart_cfg.Parity        = UART_Parity_No;
    uart_cfg.HWFlowControl = UART_HWFlowControl_None;
    uart_cfg.Mode          = UART_Mode_Rx | UART_Mode_Tx;
    UART_Init(UART1, &uart_cfg);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);

    GPIO_StructInit(&gpio_cfg);
    gpio_cfg.GPIO_Pin   = GPIO_Pin_9;
    gpio_cfg.GPIO_Speed = GPIO_Speed_High;
    gpio_cfg.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &gpio_cfg);

    gpio_cfg.GPIO_Pin  = GPIO_Pin_10;
    gpio_cfg.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA, &gpio_cfg);

    nvic_cfg.NVIC_IRQChannel = UART1_IRQn;
    nvic_cfg.NVIC_IRQChannelPreemptionPriority = 0;
    nvic_cfg.NVIC_IRQChannelSubPriority = 1;
    nvic_cfg.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_cfg);

    UART_Cmd(UART1, ENABLE);
    UART_ITConfig(UART1, UART_IT_RX|UART_IT_RXIDLE, ENABLE);
}

中断函数处理,先实现将收到的数据原样返回的功能,创建接收缓冲区,通过接收中断向缓冲区写入数据,当触发空闲中断或缓冲区写入超过一半后,开始发送数据
#define UART_BUFFER_LEN 50
uint8_t uart_buffer[UART_BUFFER_LEN] = {0};
uint8_t uart_rxindex = 0;
uint8_t uart_rxlen = 0;
uint8_t uart_txindex = 0;
uint8_t uart_txlen = 0;

void readrxtotxbuffer()
{
    uart_txlen += uart_rxlen;
    uart_rxlen = 0;
    UART_ITConfig(UART1, UART_IT_TX, ENABLE);
}

void UART1_IRQHandler(void)
{
    if(UART_GetITStatus(UART1, UART_IT_RX) == SET){
        UART_ClearITPendingBit(UART1, UART_IT_RX);
        uart_buffer[uart_rxindex++] = UART_ReceiveData(UART1);
        if(uart_rxindex == UART_BUFFER_LEN)
            uart_rxindex = 0;
        uart_rxlen++;
    }
    if(UART_GetITStatus(UART1, UART_IT_RXIDLE) == SET|| uart_rxlen == UART_BUFFER_LEN/2) {
        UART_ClearITPendingBit(UART1, UART_IT_RXIDLE);
        readrxtotxbuffer();
    }
    if(UART_GetITStatus(UART1, UART_IT_TX) == SET){
        UART_ClearITPendingBit(UART1, UART_IT_TX);
        if(uart_txlen > 0)
        {
            UART_SendData(UART1,uart_buffer[uart_txindex++]);
            if(uart_txindex == UART_BUFFER_LEN)
                uart_txindex = 0;
            uart_txlen--;
        }
        else
        {
            UART_ITConfig(UART1, UART_IT_TX, DISABLE);
        }
    }
}

运行效果

接下来实现将printf输出重定向到串口,方便打印调试信息,如果使用Keil开发的话可以很简单就实现,先勾选这个

然后添加下面这段代码
int fputc(int ch, FILE *f)
{
    UART_SendData(UART1, ch);
    while (UART_GetFlagStatus(UART1, UART_FLAG_TXC) == RESET);
    return ch;
}
在main函数中测试printf输出
int main(void)
{
    led_init();
    keys_init();
    exit_init();
    uart_init();
    printf("This is printf test! %d",666);
    while (1)
    {
    }
}

运行效果

在开发中经常会有让某个特定任务按周期运行的需要,或者对输入信号进行计数,这时候就要用到定时器了,除此之外PWM也要用到定时器,接下来实现一个1s的定时器,MM32F5330拥有的定时器资源如下

接下来使用基础定时器6实现这个1秒的定时器,先看一下系统框图,Timer6在APB1上

系统初始化时默认180MHz的时钟频率,APB1不分频,这样将Timer6的预分频系数设置为18000-1,重载值设置为10000-1就得到了一个1s触发的定时器,代码如下
void timer6_init(void)
{
    NVIC_InitTypeDef nvic_cfg;
    TIM_TimeBaseInitTypeDef timer_cfg;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

    TIM_TimeBaseStructInit(&timer_cfg);
    timer_cfg.TIM_Prescaler         = (TIM_GetTIMxClock(TIM6) / 10000 - 1);
    timer_cfg.TIM_CounterMode       = TIM_CounterMode_Up;
    timer_cfg.TIM_Period            = (10000 - 1);
    timer_cfg.TIM_ClockDivision     = TIM_CKD_Div1;
    timer_cfg.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM6, &timer_cfg);

    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);

    nvic_cfg.NVIC_IRQChannel = TIM6_IRQn;
    nvic_cfg.NVIC_IRQChannelPreemptionPriority = 0;
    nvic_cfg.NVIC_IRQChannelSubPriority = 1;
    nvic_cfg.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_cfg);

    TIM_Cmd(TIM6, ENABLE);
}

在中断中累加计数并发送
uint8_t  sec_flag = 0;
uint32_t test_count = 0;

void TIM6_IRQHandler(void)
{
    if (RESET != TIM_GetITStatus(TIM6, TIM_IT_Update))
    {
        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
        test_count += 1;
        printf("sec count %d",test_count);
    }
}

运行效果


使用特权

评论回复
沙发
地瓜patch| | 2024-6-28 14:54 | 只看该作者
万能的定时器,控制电机也要他,计数也要他

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

695

帖子

6

粉丝