stm8 串口中断接收数据 (完全中断执行)

最近写modbus ,接收的时候各种问题,放在主函数,执行子函数的时候收不到数据,不放在主函数,似乎是一个不错的想法。

 第一步:串口初始化

哪位大神指导,复制过来的中文注释都是乱码的问题,感激不尽

void UART2_Config(void)
{
  UART2_DeInit();		/* ½«¼Ä´æÆ÷µÄÖµ¸´Î» */
	
// 初始化 UART2
// 参数说明:
// - 9600: 波特率设置为9600 bps
// - UART2_WORDLENGTH_8D: 数据位长度设置为8位
// - UART2_STOPBITS_1: 停止位设置为1位
// - UART2_PARITY_NO: 不使用奇偶校验
// - UART2_SYNCMODE_CLOCK_DISABLE: 禁用同步模式时钟
// - UART2_MODE_TXRX_ENABLE: 使能发送和接收模式
UART2_Init((u32)9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO, UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);

// 配置 UART2 接收中断
// UART2_IT_RXNE_OR: 使能接收数据寄存器非空 (RXNE) 或接收超时 (OR) 中断
// ENABLE: 使能该中断
UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);

// 使能 UART2 外设
// 这一步将 UART2 外设的功能打开,使其开始工作
UART2_Cmd(ENABLE);

}

第二步:初始化 定时器  

这里可能有人好奇为啥要定时器,我是用来判断超时,防止错位的,可能有更好的办法。


// 定义全局变量,用于存储计时器的分钟、秒和毫秒
int minutes = 0;      // 存储分钟数
int seconds = 0;      // 存储秒数
int milliseconds = 0;  // 存储毫秒数

// 初始化 TIM3 定时器
void Tim3_Init(void)
{
    // 禁用 TIM3 定时器
    TIM3_Cmd(DISABLE);

    // 将 TIM3 定时器重置为默认状态
    TIM3_DeInit();

    // 配置 TIM3 的时间基准
    // 参数说明:
    // - TIM3_PRESCALER_16: 预分频器设置为 16,意味着定时器计数频率为系统时钟频率 / 16
    // - 999: 定时器计数器的自动重装载值设置为 999,意味着计数到 999 时会产生一个更新事件
    // 这样配置后,TIM3 每当计数到 1000(999 + 1)个时钟周期时,更新事件会被触发
    TIM3_TimeBaseInit(TIM3_PRESCALER_16, 999);

    // 启动 TIM3 定时器
    TIM3_Cmd(ENABLE);

    // 使能 TIM3 的更新中断
    // TIM3_IT_UPDATE: 指定要使能的中断类型,这里是更新中断
    // ENABLE: 使能更新中断,使得每次定时器计数到 1000 时会触发中断
    TIM3_ITConfig(TIM3_IT_UPDATE, ENABLE);

    // 初始化计时器的分钟、秒和毫秒变量
    minutes = 0;        // 初始化分钟数为 0
    seconds = 0;        // 初始化秒数为 0
    milliseconds = 0;   // 初始化毫秒数为 0
}

  1. 全局变量定义:

    • int minutes = 0;: 用于存储计时器的分钟数,初始值为 0。
    • int seconds = 0;: 用于存储计时器的秒数,初始值为 0。
    • int milliseconds = 0;: 用于存储计时器的毫秒数,初始值为 0。
  2. Tim3_Init 函数:

    • 该函数用于初始化 TIM3 定时器并配置其相关参数。
  3. TIM3_Cmd(DISABLE);:

    • 禁用 TIM3 定时器,确保在进行初始化时定时器处于关闭状态。
  4. TIM3_DeInit();:

    • 将 TIM3 定时器重置为默认状态,清除之前的配置和状态,以确保新的配置不会受到旧设置的影响。
  5. TIM3_TimeBaseInit(TIM3_PRESCALER_16, 999);:

    • 配置 TIM3 的时间基准。
    • TIM3_PRESCALER_16: 设置定时器的预分频器为 16,这表示定时器计数频率为系统时钟频率除以 16。
    • 999: 设置自动重装载值为 999,意味着定时器计数到 999 后会产生一个更新事件。这样配置后,TIM3 每 1000 个计数周期(即每 1000 / (系统时钟频率 / 16) 秒)将触发一次更新事件。
  6. TIM3_Cmd(ENABLE);:

    • 启动 TIM3 定时器,使其开始计数。
  7. TIM3_ITConfig(TIM3_IT_UPDATE, ENABLE);:

    • 使能 TIM3 的更新中断。
    • TIM3_IT_UPDATE: 指定要使能的中断类型,这里是更新中断。
    • ENABLE: 使能更新中断,使得每次定时器计数到 1000 时会触发中断,从而可以在中断服务例程中处理计时逻辑。
  8. 初始化计时器变量:

    • minutes = 0;: 将分钟数初始化为 0。
    • seconds = 0;: 将秒数初始化为 0。
    • milliseconds = 0;: 将毫秒数初始化为 0。

time3 中断内容


// 定义定时器3的更新、溢出和断点中断处理程序
INTERRUPT_HANDLER(TIM3_UPD_OVF_BRK_IRQHandler, 15)
{
  /* 在开发过程中,为了检测意外事件,建议在以下指令上设置一个断点。
     这可以帮助开发者在调试时观察中断处理的执行情况。 
  */

  milliseconds += 1; // 每次中断触发时,将毫秒计数增加10毫秒

  TIM3->SR1 &= ~TIM3_SR1_UIF;   // 清除更新中断标志位,表示已经处理了这次中断
  // TIM3_ClearITPendingBit(TIM3_IT_UPDATE); // 这行代码被注释掉了,功能与上行相同

  // 检查累计的毫秒数是否达到1000毫秒(即1秒)
  if (milliseconds >= 1000) 
  {
    milliseconds -= 1000; // 从毫秒计数中减去1000,准备下一秒的计数
    seconds++; // 秒数加1
    
    // 检查秒数是否达到60秒
    if (seconds >= 60) 
    {
      seconds = 0; // 如果达到60秒,重置秒数为0
      minutes++; // 分钟数加1
      
      // 检查分钟数是否超过1000分钟
      if (minutes > 1000)
      {
        minutes = 0;  // 如果分钟数超过1000,重置为0
      }
    }
  }
}

时钟计算函数   用来计算距离上次调用,过了多久

// 记录上次时间的变量
unsigned int last_minutes = 0;      // 存储上一次的分钟数
unsigned int last_seconds = 0;      // 存储上一次的秒数
unsigned int last_milliseconds = 0;  // 存储上一次的毫秒数

u32 interval; // 用于存储当前时间与上次时间的间隔

// 函数:计算当前时间与上次记录时间之间的间隔
u32 check_time_interval() 
{
    // 计算当前时间(以毫秒为单位)
    u32 current_time_in_ms = (minutes * 60 * 1000) + (seconds * 1000) + milliseconds;
    // 计算上次记录的时间(以毫秒为单位)
    u32 last_time_in_ms = (last_minutes * 60 * 1000) + (last_seconds * 1000) + last_milliseconds;

    // 计算当前时间与上次时间的间隔(单位:毫秒)
    interval = current_time_in_ms - last_time_in_ms;

    // 更新上次记录的时间为当前时间
    last_minutes = minutes; // 更新上次分钟数
    last_seconds = seconds; // 更新上次秒数
    last_milliseconds = milliseconds; // 更新上次毫秒数
    
    // 返回当前时间与上次时间的间隔
    return interval;
}

第三步: 设置中断内容

我这里是如果接收到的内容,正好是从机编号,则送入解析内容。不过貌似解析时间不能太久,后面容易丢包。我的处理办法是,如果解析时间太长,就先做标记,等数据接收完成后。再去处理函数。

// UART2 接收中断处理程序
INTERRUPT_HANDLER(UART2_RX_IRQHandler, 21)
{
    // 清除 UART2 接收中断挂起位
    // 这里清除的是 RXNE 中断,而不是 RXNE_OR 中断
    UART2_ClearITPendingBit(UART2_IT_RXNE);
  
    // 检查时间间隔是否大于 10 毫秒
    if (check_time_interval() > 10)
    {
        read_idx = 0;  // 重置读取索引
        (void) UART2->SR; // 读取 UART 状态寄存器以清除潜在的错误标志
        (void) UART2->DR; // 读取 UART 数据寄存器以清除潜在的错误标志
    }
  
    // 从 UART2 接收数据并存入缓冲区
    read_buffer[read_idx++] = UART2_ReceiveData8();
  
    // 检查是否达到了预设的读取长度
    if (read_idx >= read_len) // 如果读取的字节数大于等于预设的长度
    {
        UART2_ITConfig(UART2_IT_RXNE_OR, DISABLE); // 禁用接收中断
        read_ok = 1; // 标记读取完成
        read_idx = 0; // 重置读取索引
        (void) UART2->SR; // 读取 UART 状态寄存器以清除潜在的错误标志
        (void) UART2->DR; // 读取 UART 数据寄存器以清除潜在的错误标志
    }
  
    // 如果读取完成标志为 1
    if (read_ok == 1)
    {
        // 如果接收到的数据的第一个字节是 SlaveID
        if (read_buffer[0] == SlaveID)
        {
            DisposeReceive(); // 处理接收到的数据
        }
        
        // 重新使能 UART2 接收中断
        UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);
        read_ok = 0; // 重置读取完成标志
    }
}

要下载STM32串口中断接收数据程序,需要按照以下步骤进行操作: 1. 首先需要准备好开发环境,包括ST-Link下载调试器、编程软件(如Keil、IAR等)、USB转串口模块等。 2. 确保硬件连接正确。将STM32单片机与ST-Link下载调试器通过JTAG/SWD接口相连,将USB转串口模块的TX和RX引脚分别与STM32单片机的相应串口引脚相连。 3. 在编程软件中创建一个新的工程,并添加相应的库文件。打开文件->新建->MDK-ARM Project,然后选择对应的芯片型号。 4. 在工程中添加对应的串口库文件,例如“stm32f10x_usart.h”和“stm32f10x_usart.c”。 5. 配置串口的中断接收。在main函数中,通过设置USART_InitTypeDef结构体参数,配置相应串口的波特率、数据位、停止位等参数。然后通过NVIC_Configuration函数开启串口的中断。 6. 实现串口接收中断函数。在stm32f10x_it.c文件中,找到USARTx_IRQHandler函数。在该函数中编写串口接收数据的处理代码。例如,可以通过判断USART_GetITStatus(USARTx, USART_IT_RXNE)的返回值来判断是否收到数据,并通过USART_ReceiveData(USARTx)读取接收到的数据。 7. 编译并下载程序。在编程软件中点击“Build”,编译源代码并生成bin或hex文件。然后使用ST-Link下载调试器将生成的bin或hex文件下载到STM32单片机中。 8. 在STM32单片机上运行程序。将USB转串口模块连接电脑,并通过串口调试软件(如Tera Term)打开串口进行数据接收。 通过以上步骤,即可成功下载STM32串口中断接收数据程序,并实现数据的接收和处理。不过要注意,在编写代码过程中,需要根据具体的芯片型号和组件进行相应的配置和调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值