这里的demo是1对1的通讯的,1对多修改协议增加从机地址字段,并修改相关使用即可,这里截取项目中一个通讯任务。
硬件平台 STM32 系统 freertos
// #inlcude 略
typedef struct{
uint8_t len;
uint8_t msg;
uint8_t payloadLen;
}_msg;
#define FRAME_END_TIME 50//ms
#define RX_BUFFER_SIZE 256
#define TX_BUFFER_SIZE 256
static uint8_t RxBuffer[RX_BUFFER_SIZE];
static uint8_t TxBuffer[TX_BUFFER_SIZE];
static uint16_t Rx_p=0;
static uint8_t FrameStatus=1;
static int nowRxTick=-1;
static int lastRxTicke=0;
extern uint32_t Sys_ms_Tick;//递增
extern uint8_t Source[];
extern uint8_t Destination[];
extern char IMEI[];
extern char IOT_IP[];
extern char NB_IOT_NET[];
static void InterruptReviceCallback(uint8_t a)
{
if(0==FrameStatus)
{
if(Rx_p<RX_BUFFER_SIZE)
{
RxBuffer[Rx_p++] = a;
}
nowRxTick = Sys_ms_Tick;
}
}
static void ReviceBegin()
{
if(FrameStatus==1)
{
FrameStatus = 0;
Rx_p = 0;
nowRxTick = -1;
lastRxTicke = 0;
}
}
static int GetFrame()
{
if(nowRxTick!=-1)
{
if(nowRxTick==lastRxTicke)
{
FrameStatus = 1;
return 1;
}
else
{
lastRxTicke = nowRxTick;
return 0;
}
}
return 0;
}
static void SendFrame()
{
uint16_t crc16;
uint8_t len = TxBuffer[0];
crc16 = Crc16_Modbus(TxBuffer,len-2);
TxBuffer[len-2] = crc16;
TxBuffer[len-1] = crc16>>8;
HAL_UART_Transmit(&huart1,TxBuffer,len,0xffff);
}
void DebugInit()
{
UART1_Callback = InterruptReviceCallback;//回调估值
StartUART_Rx(&huart1);//启动串口驱动
FrameStatus=1;
Urt1ReviceBegin();//开始接收
}
void DebugTask()
{
_msg *rmsg=(_msg*)RxBuffer;
_msg *tmsg=(_msg*)TxBuffer;
uint8_t *rpayload = &RxBuffer[3];
uint8_t *tpayload = &TxBuffer[3];
uint8_t len=0;
uint16_t temp;
DebugInit();
while(1)
{
osDelay(FRAME_END_TIME);
if(GetUsart1Frame())
{
if(0==Crc16_Modbus(RxBuffer,Rx_p))
{
switch(rmsg->msg)
{
case 0x01:
tmsg->len=5+6;
tmsg->msg=0x81;
tmsg->payloadLen=6;
memcpy(tpayload,Source,6);
SendFrame();
break;
case 0x02:
if(rmsg->len==11)
{
memcpy(Source,rpayload,6);
}
tmsg->len=5+0;
tmsg->msg=0x82;
tmsg->payloadLen=0;
SendFrame();
break;
case 0x03:
tmsg->len=5+6;
tmsg->msg=0x83;
tmsg->payloadLen=6;
memcpy(tpayload,Destination,6);
SendFrame();
break;
case 0x04:
memcpy(Destination,rpayload,6);
tmsg->len=5+0;
tmsg->msg=0x84;
tmsg->payloadLen=0;
SendFrame();
break;
case 0x05:
tmsg->len=5+strlen(IMEI)+1;
tmsg->msg=0x85;
tmsg->payloadLen=strlen(IMEI)+1;
memcpy(tpayload,IMEI,strlen(IMEI)+1);
SendFrame();
break;
case 0x06:
tmsg->len=5+strlen(IOT_IP)+1;
tmsg->msg=0x86;
tmsg->payloadLen=strlen(IOT_IP)+1;
memcpy(tpayload,IOT_IP,strlen(IOT_IP)+1);
SendFrame();
break;
case 0x07:
len = strlen((char*)rpayload);
if(len<64)
{
memcpy(IOT_IP,rpayload,strlen((char*)rpayload));
tmsg->len=5+1;
tmsg->msg=0x87;
tmsg->payloadLen=1;
tpayload[0] = 0;
SendFrame();
}
else
{
tmsg->len=5+1;
tmsg->msg=0x87;
tmsg->payloadLen=1;
tpayload[0] = 1;
SendFrame();
}
break;
case 0x08:
tmsg->len=5+strlen(NB_IOT_NET)+1;
tmsg->msg=0x88;
tmsg->payloadLen=strlen(NB_IOT_NET)+1;
memcpy(tpayload,NB_IOT_NET,strlen(NB_IOT_NET)+1);
SendFrame();
break;
case 0x09:
len = strlen((char*)rpayload);
if(len<64)
{
memcpy(NB_IOT_NET,rpayload,strlen((char*)rpayload));
tmsg->len=5+1;
tmsg->msg=0x89;
tmsg->payloadLen=1;
tpayload[0] = 0;
SendFrame();
}
else
{
tmsg->len=5+1;
tmsg->msg=0x89;
tmsg->payloadLen=1;
tpayload[0] = 1;
SendFrame();
}
break;
case 0x0a:
SaveSysInfo();
tmsg->len=5;
tmsg->msg=0x8a;
tmsg->payloadLen=0;
SendFrame();
break;
case 0x0b:
memset(Source,0,6);
Source[5]=1;
memset(Destination,0,6);
Destination[5]=1;
strcpy(IMEI,"000000000");
strcpy(IOT_IP,"AT+NCDP=180.101.147.115,5683\r\n");
strcpy(NB_IOT_NET,"AT+CGDCONT=1,\"IP\",\"ctnet\"\r\n");
SaveSysInfo();
SYS.uploadTime = 60;
SaveInitInfo();
tmsg->len=5;
tmsg->msg=0x8b;
tmsg->payloadLen=1;
SendFrame();
break;
case 0x0c:
tmsg->len=5+strlen(COMPY_ID)+1;
tmsg->msg=0x8c;
tmsg->payloadLen=strlen(COMPY_ID)+1;
memcpy(tpayload,COMPY_ID,strlen(COMPY_ID)+1);
SendFrame();
break;
case 0x0d:
SYS.terminalMode=0;
SaveInitInfo();
osDelay(50);
printf("搜索准备成功正在重启\r\n");
HAL_NVIC_SystemReset();
break;
case 0x0e:
SYS.terminalMode=2;
SaveInitInfo();
SaveTerminalInfo();
osDelay(50);
printf("保存成功正在重启\r\n");
HAL_NVIC_SystemReset();
break;
case 0x0f:
printf("det%d个,arc%d个,ocp%d个,mmn%d个\r\n",SYS.detectorNum,SYS.arcDetectorNum,SYS.ocpNum,SYS.multiMeterNum);
break;
case 0x10:
temp = rpayload[0]|rpayload[1]<<8;
if(temp>0&&temp<2000)
{
SYS.uploadTime = temp;
SaveInitInfo();
tmsg->len=5+1;
tmsg->msg=0x90;
tmsg->payloadLen=1;
tpayload[0] = 0;
SendFrame();
}
else
{
tmsg->len=5+1;
tmsg->msg=0x90;
tmsg->payloadLen=1;
tpayload[0] = 1;
SendFrame();
}
break;
case 0x11:
tmsg->len=5+2;
tmsg->msg=0x91;
tmsg->payloadLen=2;
tpayload[0] = SYS.uploadTime;
tpayload[1] = SYS.uploadTime>>8;
SendFrame();
break;
case 0x7f:
tmsg->len=5;
tmsg->msg=0xff;
tmsg->payloadLen=0;
SendFrame();
osDelay(50);
HAL_NVIC_SystemReset();
break;
default:break;
}
}
ReviceBegin();
}
}
}
根据主机设置好超时参数
FRAME_END_TIME,连续的两个字节时间超过FRAME_END_TIME即判断为一帧完成,这里借鉴了modbus-rtu断帧方式。
freertos开机新建一个任务,然后把DebugInit()放到while(1)中即可,底层硬件初始化略,UART1_Callback()串口中断回掉函数,Sys_ms_Tick 1ms 自增1