Modbus收发定时器加串口中断实现

(以下代码是基于HAL库写的,标准库下需要适当修改)

首先,需要一个MODBUS结构体:

typedef struct
{
   unsigned char myadd;  //本机地址
    u8 rcbuf[100];  //Modbus接收缓存
    u16 timout;  //Modbus的数据断续时间
    u8 recount;   //Modbus接收到的数据数量
    u8 timrun;  //modbus定时器是否计时
    u8 reflag; //收到一帧数据的标记
    u8 *Sendbuf;  //Modbus发送缓存
    

}MODBUS;

定时器的配置:

//通用定时器3中断初始化
//arr自动重装值
//psc时钟预分频数

void TIM3_Init(u16 arr,u16 psc)
{  
    TIM3_Handler.Instance=TIM3;                          //ͨÓö¨Ê±Æ÷3
    TIM3_Handler.Init.Prescaler=psc;                     //·ÖƵϵÊý
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;    //ÏòÉϼÆÊýÆ÷
    TIM3_Handler.Init.Period=arr;                        //×Ô¶¯×°ÔØÖµ
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//ʱÖÓ·ÖƵÒò×Ó
    HAL_TIM_Base_Init(&TIM3_Handler);
    
    HAL_TIM_Base_Start_IT(&TIM3_Handler); //ʹÄܶ¨Ê±Æ÷3ºÍ¶¨Ê±Æ÷3¸üÐÂÖжϣºTIM_IT_UPDATE   
    
}

//¶¨Ê±Æ÷µ×²áÇý¶¯£¬¿ªÆôʱÖÓ£¬ÉèÖÃÖжÏÓÅÏȼ¶
//´Ëº¯Êý»á±»HAL_TIM_Base_Init()º¯Êýµ÷ÓÃ
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM3)
    {
        __HAL_RCC_TIM3_CLK_ENABLE();            //ʹÄÜTIM3ʱÖÓ
        HAL_NVIC_SetPriority(TIM3_IRQn,1,3);    //ÉèÖÃÖжÏÓÅÏȼ¶£¬ÇÀÕ¼ÓÅÏȼ¶1£¬×ÓÓÅÏȼ¶3
        HAL_NVIC_EnableIRQ(TIM3_IRQn);          //¿ªÆôITM3ÖжϠ  
    }
     if(htim->Instance==TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();            //ʹÄÜTIM3ʱÖÓ
        HAL_NVIC_SetPriority(TIM2_IRQn,1,3);    //ÉèÖÃÖжÏÓÅÏȼ¶£¬ÇÀÕ¼ÓÅÏȼ¶1£¬×ÓÓÅÏȼ¶3
        HAL_NVIC_EnableIRQ(TIM2_IRQn);          //¿ªÆôITM3ÖжϠ  
    }
}

//¶¨Ê±Æ÷3ÖжϷþÎñº¯Êý
void TIM3_IRQHandler(void)
{
    
    HAL_TIM_IRQHandler(&TIM3_Handler);
     TIM_HandleTypeDef TIM3_Handler;  
      u8 st;
    
    
    //if((TIM3_Handler.Instance->SR &(TIM_FLAG_UPDATE))!=0)
    //{
    //    ((TIM3_Handler).Instance->SR = ~(TIM_FLAG_UPDATE));
        if(modbus.timrun!=0)
        {
           modbus.timout++;
            if(modbus.timout>=8)
            {
              modbus.timrun=0; //¹Ø±Õ¶¨Ê±
                modbus.reflag=1; //ÊÕµ½Ò»Ö¡Êý¾Ý
              //modbus.recount=0;
            }
        }
        
    //}
}

 

串口配置:


void Modbus_uart4_init(u32 bound)                    //´®¿Ú3ÅäÖÃ
{
    // NVIC_InitTypeDef NVIC_InitStructure;   
  __HAL_RCC_GPIOC_CLK_ENABLE();            //ʹÄÜGPIOBʱÖÓ
    
    do{
            __IO uint32_t tmpreg;
            SET_BIT(RCC->APB1ENR, RCC_APB1ENR_UART4EN);
            /* Delay after an RCC peripheral clock enabling */
            tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_UART4EN);
            UNUSED(tmpreg);
        }while(0);

    
    //RCC->APB1ENR|=1<<19;   //ʹÄÜUSART4ʱÖÓ

    //__HAL_RCC_UART4_CLK_ENABLE();
 // __HAL_RCC_USART4_CLK_ENABLE();            //ʹÄÜUSART4ʱÖÓ ¡¤
    

    //GPIO¶Ë¿ÚÉèÖÃ
    GPIO_InitTypeDef GPIO_Initure;
  GPIO_Initure.Pin=GPIO_PIN_10;             //PC10
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;        //¸´ÓÃÍÆÍìÊä³ö
    GPIO_Initure.Pull=GPIO_PULLUP;            //ÉÏÀ­
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;        //¸ßËÙ
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);           //³õʼ»¯PB10
    
    GPIO_Initure.Pin=GPIO_PIN_11;             //PB11
    GPIO_Initure.Mode=GPIO_MODE_AF_INPUT;    //¸´ÓÃÊäÈë
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);           //³õʼ»¯PB11
    


  UART4_E70Handler.Instance=UART4;      //UART4
     UART4_E70Handler.Init.BaudRate=bound;                //²¨ÌØÂÊ
    UART4_E70Handler.Init.WordLength=UART_WORDLENGTH_8B;    //×Ö³¤Îª8λÊý¾Ý¸ñʽ
    UART4_E70Handler.Init.StopBits=UART_STOPBITS_1;        //Ò»¸öֹͣλ
    UART4_E70Handler.Init.Parity=UART_PARITY_NONE;        //ÎÞÆæżУÑéλ
    UART4_E70Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;    //ÎÞÓ²¼þÁ÷¿Ø
    UART4_E70Handler.Init.Mode=UART_MODE_TX_RX;            //ÊÕ·¢Ä£Ê½
    HAL_UART_Init(&UART4_E70Handler);                    //HAL_UART_Init()»áʹÄÜUSART3
    
  __HAL_UART_DISABLE_IT(&UART4_E70Handler,UART_IT_TC);
#if 1
    __HAL_UART_ENABLE_IT(&UART4_E70Handler,UART_IT_RXNE);//¿ªÆô½ÓÊÕÖжÏ
    HAL_NVIC_EnableIRQ(UART4_IRQn);                        //ʹÄÜUSART4ÖжÏ
    HAL_NVIC_SetPriority(UART4_IRQn,3,3);                    //ÇÀÕ¼ÓÅÏȼ¶3£¬×ÓÓÅÏȼ¶3
#endif    
      
}

void UART4_IRQHandler()  //modbus×Ö½Ú½ÓÊÕÖжÏ
{
  u8 st,sbuf;
    //st=USART_GetITStatus(USART3,USART_IT_RXNE);
 st=(__HAL_UART_GET_FLAG(&UART4_E70Handler,UART_FLAG_RXNE)!=RESET);
    if(st==SET)
    {
      sbuf=UART4->DR;
        
        if(modbus.reflag==1) //ÓÐÊý¾Ý°üÕýÔÚ´¦Àí
        {
           return ;
        }
        
      modbus.rcbuf[modbus.recount++]=sbuf;
        modbus.timout=0;
        if(modbus.recount==1) //ÊÕµ½Ö÷»ú·¢À´µÄÒ»Ö¡Êý¾ÝµÄµÚÒ»×Ö½Ú
        {
         modbus.timrun=1;  //Æô¶¯¶¨Ê±
        }
    }
}

void uart_send_data(u8 *buf,u8 len)
{
  HAL_UART_Transmit(&UART4_E70Handler,buf,len,1000);//´®¿Ú·¢ËÍÊý¾Ý
}


接下来是modbus事件处理函数,也是接收消息的函数:

void Modbus_Event()
{
    u16 crc;
    u16 recrc;
    u8 k;
  if(modbus.reflag==0)
    {
      return ;
    }
    
    
    

  if(modbus.rcbuf[3]== modbus.myadd)
    {    
    crc=usMBCRC16(&modbus.rcbuf [3],modbus.recount-5);
  recrc=modbus.rcbuf[modbus.recount-1]*256+modbus.rcbuf[modbus.recount-2];
      
    if(crc==recrc)  //Êý¾Ý°ü·ûºÏУÑé¹æÔò
     {
             if(modbus.rcbuf[4]==0x02)
            {
                LCD_ShowString(30,130,200,16,16,"send ok");
            }
    
        if(modbus.rcbuf[4]==0x03)
            {
                LCD_ShowString(30,130,200,16,16,"Read ok");
            }
            if(modbus.rcbuf[4]==0x06)
            {
                LCD_ShowString(30,130,200,16,16,"write ok");
            }
            
            for (i=0; i<modbus.recount; i++)
            {
                temp = modbus.rcbuf[i]&0xf0;
                lcd_show[2*i] = IntToHexChar(temp >> 4);
                temp = modbus.rcbuf[i]&0x0f;
                lcd_show[2*i+1] = IntToHexChar(temp);
            }
                LCD_ShowString(30,150,300,16,16,lcd_show);
            
     }
    
 }
     // free(modbus.rcbuf);//ÊÍ·ÅÄÚ´æ
      modbus.recount=0;
        modbus.reflag=0;
}


接下来来看一下总体的思路。

首先,初始化时,modbus.myadd=1;  modbus.timrun=0; //定时器停止,开机,定时器并不计时,触发接收中断,判断是否正在处理数据,若无,直接收到缓冲区,并开始计时, 让modbus.timout=0;,定时器不断计时,但又被中断清零,直至没有收到消息,接收结束,开始处理,处理完后可重新接收。

 

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值