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

[复制链接]
 楼主| yuyy1989 发表于 2024-6-22 19:58 | 显示全部楼层 |阅读模式
<
这次来完成这两个题目
微信截图_20240622172005.png
UART,即通用异步接收器/发送器,是嵌入式开发中最常用的设备间通信协议之一,在开发中经常会用它来打印调试信息,可以最少使用2个引脚(TX和RX)实现数据传输(设备间需要共地),如果是单向传输可以只用一个引脚,开发板上已经实现了USB转UART的电路,使用引脚是PA9和PA10
微信截图_20240622172823.png
使用串口涉及到GPIO复用功能,复用表可以在数据手册中找到
微信截图_20240622173248.png
初始化串口,波特率设置为115200,停止位1,无校验,开启接收中断和空闲中断
  1. void uart_init(void)
  2. {
  3.     GPIO_InitTypeDef gpio_cfg;
  4.     NVIC_InitTypeDef nvic_cfg;
  5.     UART_InitTypeDef uart_cfg;

  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);
  7.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  8.     UART_StructInit(&uart_cfg);
  9.     uart_cfg.BaudRate      = 115200;
  10.     uart_cfg.WordLength    = UART_WordLength_8b;
  11.     uart_cfg.StopBits      = UART_StopBits_1;
  12.     uart_cfg.Parity        = UART_Parity_No;
  13.     uart_cfg.HWFlowControl = UART_HWFlowControl_None;
  14.     uart_cfg.Mode          = UART_Mode_Rx | UART_Mode_Tx;
  15.     UART_Init(UART1, &uart_cfg);

  16.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
  17.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);

  18.     GPIO_StructInit(&gpio_cfg);
  19.     gpio_cfg.GPIO_Pin   = GPIO_Pin_9;
  20.     gpio_cfg.GPIO_Speed = GPIO_Speed_High;
  21.     gpio_cfg.GPIO_Mode  = GPIO_Mode_AF_PP;
  22.     GPIO_Init(GPIOA, &gpio_cfg);

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

  26.     nvic_cfg.NVIC_IRQChannel = UART1_IRQn;
  27.     nvic_cfg.NVIC_IRQChannelPreemptionPriority = 0;
  28.     nvic_cfg.NVIC_IRQChannelSubPriority = 1;
  29.     nvic_cfg.NVIC_IRQChannelCmd = ENABLE;
  30.     NVIC_Init(&nvic_cfg);

  31.     UART_Cmd(UART1, ENABLE);
  32.     UART_ITConfig(UART1, UART_IT_RX|UART_IT_RXIDLE, ENABLE);
  33. }

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

  7. void readrxtotxbuffer()
  8. {
  9.     uart_txlen += uart_rxlen;
  10.     uart_rxlen = 0;
  11.     UART_ITConfig(UART1, UART_IT_TX, ENABLE);
  12. }

  13. void UART1_IRQHandler(void)
  14. {
  15.     if(UART_GetITStatus(UART1, UART_IT_RX) == SET){
  16.         UART_ClearITPendingBit(UART1, UART_IT_RX);
  17.         uart_buffer[uart_rxindex++] = UART_ReceiveData(UART1);
  18.         if(uart_rxindex == UART_BUFFER_LEN)
  19.             uart_rxindex = 0;
  20.         uart_rxlen++;
  21.     }
  22.     if(UART_GetITStatus(UART1, UART_IT_RXIDLE) == SET|| uart_rxlen == UART_BUFFER_LEN/2) {
  23.         UART_ClearITPendingBit(UART1, UART_IT_RXIDLE);
  24.         readrxtotxbuffer();
  25.     }
  26.     if(UART_GetITStatus(UART1, UART_IT_TX) == SET){
  27.         UART_ClearITPendingBit(UART1, UART_IT_TX);
  28.         if(uart_txlen > 0)
  29.         {
  30.             UART_SendData(UART1,uart_buffer[uart_txindex++]);
  31.             if(uart_txindex == UART_BUFFER_LEN)
  32.                 uart_txindex = 0;
  33.             uart_txlen--;
  34.         }
  35.         else
  36.         {
  37.             UART_ITConfig(UART1, UART_IT_TX, DISABLE);
  38.         }
  39.     }
  40. }

运行效果
微信截图_20240622183328.png
接下来实现将printf输出重定向到串口,方便打印调试信息,如果使用Keil开发的话可以很简单就实现,先勾选这个
微信截图_20240622183543.png
然后添加下面这段代码
  1. int fputc(int ch, FILE *f)
  2. {
  3.     UART_SendData(UART1, ch);
  4.     while (UART_GetFlagStatus(UART1, UART_FLAG_TXC) == RESET);
  5.     return ch;
  6. }
  7. 在main函数中测试printf输出
  8. int main(void)
  9. {
  10.     led_init();
  11.     keys_init();
  12.     exit_init();
  13.     uart_init();
  14.     printf("This is printf test! %d",666);
  15.     while (1)
  16.     {
  17.     }
  18. }

运行效果
微信截图_20240622183848.png
在开发中经常会有让某个特定任务按周期运行的需要,或者对输入信号进行计数,这时候就要用到定时器了,除此之外PWM也要用到定时器,接下来实现一个1s的定时器,MM32F5330拥有的定时器资源如下
微信截图_20240622184445.png
接下来使用基础定时器6实现这个1秒的定时器,先看一下系统框图,Timer6在APB1上
微信截图_20240622190028.png
系统初始化时默认180MHz的时钟频率,APB1不分频,这样将Timer6的预分频系数设置为18000-1,重载值设置为10000-1就得到了一个1s触发的定时器,代码如下
  1. void timer6_init(void)
  2. {
  3.     NVIC_InitTypeDef nvic_cfg;
  4.     TIM_TimeBaseInitTypeDef timer_cfg;

  5.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

  6.     TIM_TimeBaseStructInit(&timer_cfg);
  7.     timer_cfg.TIM_Prescaler         = (TIM_GetTIMxClock(TIM6) / 10000 - 1);
  8.     timer_cfg.TIM_CounterMode       = TIM_CounterMode_Up;
  9.     timer_cfg.TIM_Period            = (10000 - 1);
  10.     timer_cfg.TIM_ClockDivision     = TIM_CKD_Div1;
  11.     timer_cfg.TIM_RepetitionCounter = 0;
  12.     TIM_TimeBaseInit(TIM6, &timer_cfg);

  13.     TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);

  14.     nvic_cfg.NVIC_IRQChannel = TIM6_IRQn;
  15.     nvic_cfg.NVIC_IRQChannelPreemptionPriority = 0;
  16.     nvic_cfg.NVIC_IRQChannelSubPriority = 1;
  17.     nvic_cfg.NVIC_IRQChannelCmd = ENABLE;
  18.     NVIC_Init(&nvic_cfg);

  19.     TIM_Cmd(TIM6, ENABLE);
  20. }

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

  3. void TIM6_IRQHandler(void)
  4. {
  5.     if (RESET != TIM_GetITStatus(TIM6, TIM_IT_Update))
  6.     {
  7.         TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
  8.         test_count += 1;
  9.         printf("sec count %d",test_count);
  10.     }
  11. }

运行效果
微信截图_20240622194143.png

地瓜patch 发表于 2024-6-28 14:54 | 显示全部楼层
万能的定时器,控制电机也要他,计数也要他
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部
认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部