(以下代码是基于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
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;,定时器不断计时,但又被中断清零,直至没有收到消息,接收结束,开始处理,处理完后可重新接收。