/****************************************************************************************
模拟多MCU 模拟多机485通信
文件:bspthread.h
编者:张永辉 2013年8月26日
*****************************************************************************************/
/*****************************防止二次定义***********************************************/
#ifndef __BSPTHREAD_H__
#define __BSPTHREAD_H__
#include "\embed\source\lib\basetype.h"
#include "\embed\source\lib\modfifo.h"
#include "\embed\source\lib\math1.h"
//***********************************通信声明*********************************************
//机制:任何一个发,其他都会收到数据
#define U1BUF_LEN 100
Char_Fifo_Type U1R;
char U1BUF[U1BUF_LEN];
#define U2BUF_LEN 100
Char_Fifo_Type U2R;
char U2BUF[U2BUF_LEN];
#define U3BUF_LEN 100
Char_Fifo_Type U3R;
char U3BUF[U3BUF_LEN];
#define U4BUF_LEN 100
Char_Fifo_Type U4R;
char U4BUF[U4BUF_LEN];
int BspUart1Init__(void);
UINT32 BspUart1Sends__(u8 *sddata,unsigned int cnt);
UINT32 BspUart1Recvs__(u8 *rddata,unsigned int cnt,u32 timeout);
int BspUart2Init__(void);
UINT32 BspUart2Sends__(u8 *sddata,unsigned int cnt);
UINT32 BspUart2Recvs__(u8 *rddata,unsigned int cnt,u32 timeout);
int BspUart3Init__(void);
UINT32 BspUart3Sends__(u8 *sddata,unsigned int cnt);
UINT32 BspUart3Recvs__(u8 *rddata,unsigned int cnt,u32 timeout);
int BspUart4Init__(void);
UINT32 BspUart4Sends__(u8 *sddata,unsigned int cnt);
UINT32 BspUart4Recvs__(u8 *rddata,unsigned int cnt,u32 timeout);
//***********************************线程声明*********************************************
//用于模拟4个MCU
void BspThread1(void * arg);
void BspThread2(void * arg);
void BspThread3(void * arg);
void BspThread4(void * arg);
/************************函数声明********************************************************/
void BspRS485MasterRead_req(u8 id,u8 addr); //主机请求读数据
u8 BspRS485MasterRead_ret(u8 *id,u8 *addr,u8 *datas); //主机接收读到的数据(100MS)
u8 BspRS485Slver_Listing(u8 id , u8 *addr,u8 *datas); //从机监听主机的命令
u8 BspRS485Slver_respd(u8 id,u8 addr,u8 *datas); //从机回复主机
void BspThreadTest(void);
void BspThreadInit(void);
/***********************防止二次定义*****************************************************/
#endif
/*****************************************************************************************
数据传输操作
文件:bspthread.c
用途:使用多线程模拟多MCU的情况
*****************************************************************************************/
/* 协议
机制:
主机将从机看成是一段内存,主机只要对其按地址读写即可。
格式:
Head: ==0XAA;
xor : 校验值
ID : 主机ID==0 从机ID==1..N
所以:主机向从机发送数据时ID=[1..N] 从机发数据时ID==0
WR : ==1表示写数据 ==0读数据
所以:主机要读取数据时 WR==0 da数据区无值。 从机返回时此值保持不变
addr: 地址空间主机将从机看成内存块,addr是要读/写的开始地址 每个地址对应有8个数据
dax : addr所对应的8个数据
主机发送的数据包中 ID!=0, 接收时只接收ID==0的包。
主机发送数据后,最长在0.2秒后接收数据。
方式:主从房市。 每次通信由主机发起。
从机应该有容错机制。
假设串口波特率=9600
场景一:主机读命令
1 主机发送读指令(4byte) 至从机接收完。 最快4.16mS。 可以假设从机查询时间是10MS
2 从机回复主机(12byte) 主机接收完毕。 最快12.48mS。共计10 + 16.74mS = 26.74ms
补充:
3 当有4个从机时。主机应该有如下延时
1 主发读命令至 1号从机,并接收1号返回。
2 此时,2号从机接收到了所有的数据 共12+4Byte。最多20ms内可以处理掉这些数据。
场景二:主机写命令
1 主机发送写指令(12byte) 至从机接收完。 最快12.48mS。此从机不应答。可以假设从机查询时间是10MS 共计22.48mS
*/
#define __BSPTHREAD_C__ //文件标识
#include <Windows.h>
#include <process.h>
#include <stdio.h>
#include "bspThread.h"
#include "bsptime.h"
//------------------------------数据传输包------------------------------------------------
typedef struct
{
u8 Head; //固定0xAA
u8 Xor; //校验
u8 ID:7; //器件ID,从机ID
u8 WR:1; //==1W ==0R
u8 IshaveDa:1; //==0无数据 ==1有8个数据
u8 addr:7; //存储地址 每个地址8个数据
u8 da0; //8个数据 读的时候无数据
u8 da1;
u8 da2;
u8 da3;
u8 da4;
u8 da5;
u8 da6;
u8 da7;
}RS485_pakg;
//------------------------------内部函数-------------------------------------------------
void BspRS485MasterRead_test(u8 id,u8 addr);
void BspRS485MasterWrite_test(u8 id,u8 addr);
void BspRS485Slver_ret_msg_show(u8 i,u8 id,u8 addr,u8*da);
void BspRS485Slver_recv_msg_show(u8 i,u8 id,u8 addr,u8*da);
/****************************************************************************************
主线程
****************************************************************************************/
void BspThreadTest(void)
{
while (1)
{
Sleep(1000);
}
}
void BspThreadInit(void)
{
BspUart1Init__();
BspUart2Init__();
BspUart3Init__();
BspUart4Init__();
_beginthread(BspThread1,0,NULL);
_beginthread(BspThread2,0,NULL);
_beginthread(BspThread3,0,NULL);
_beginthread(BspThread4,0,NULL);
}
/****************************************************************************************
线程
****************************************************************************************/
//16进制显示数值
void BspBdg0X2(u8 x)
{
char a[]="0123456789ABCEDF";
u8 b = x&0x0f;
char s[5];
s[0] = '0';
s[1] = 'X';
b = (x>>4)&0x0f;
s[2] = a[b];
b = x&0x0f;
s[3] = a[b];
s[4] = '\0';
printf("%s",s);
}
//-------------------主机-----------------------------------------------------------------
RS485_pakg MTpkg;
/* 数据读取请求
参数: id 从机id号 [1-127]
addr 从机的内存起始地址 [0-127] */
void BspRS485MasterRead_req(u8 id,u8 addr)
{
//发送数据包
MTpkg.Head =0xaa;
MTpkg.ID = id;
MTpkg.WR = 0;
MTpkg.IshaveDa = 0;
MTpkg.addr = addr;
MTpkg.Xor = MathXor( (u8*)(&MTpkg.Xor + 1),2);
BspUart1Sends__((u8*)&MTpkg.Head,4);
}
/* 数据读取返回
参数: 无
返回: 返回==0 没有接收到返回数据
返回==8 接收了数据,个数==8个
*id 从机的id号 [1-127]
*addr 从机的内存起始地址 [0-127]
*data 从机的内存的数据 8个 */
u8 BspRS485MasterRead_ret(u8 *id,u8 *addr,u8 *datas)
{
u8 i;
//接收数据包
i = BspUart1Recvs__((u8*)&MTpkg.Head,sizeof(MTpkg),10);
if( i != sizeof(MTpkg))
{
return 0;
}
if (MTpkg.Head != 0xaa || MTpkg.WR != 1 || MTpkg.IshaveDa != 1)
{
return 0;
}
i = (u8)MathXor( (u8*)(&MTpkg.Xor + 1),sizeof(MTpkg)-2);
if( i!= MTpkg.Xor)
{
return 0;
}
*id = MTpkg.ID;
*addr = MTpkg.addr;
MathMemCopy(datas,&MTpkg.da0,8);
return 8;
}
/* 主机向从机写入数据
参数: id 从机id [1-127]
addr 从机内存 [1-127]
data 主机要发送的8个数据
*/
u8 BspRS485MasterWrite(u8 id,u8 addr,u8 *datas)
{
MTpkg.Head =0xaa;
MTpkg.ID = id;
MTpkg.WR = 1;
MTpkg.IshaveDa = 1;
MTpkg.addr = addr;
MathMemCopy(&MTpkg.da0,datas,8);
MTpkg.Xor = MathXor( (u8*)(&MTpkg.Xor + 1),10);
BspUart1Sends__((u8*)&MTpkg.Head,12);
return 8;
}
//[测试]主机读数据
void BspRS485MasterRead_test(u8 id,u8 addr)
{
u8 rid;
u8 datas[8];
int i;
printf("\n=============master start==============\n");
printf("main read cmd:\n");
printf(" id = %d\n",id);
printf(" addr = %d\n",addr);
printf(" cmd = read\n");
BspRS485MasterRead_req(id,addr); //呼叫
Sleep(50);
i = BspRS485MasterRead_ret(&rid,&addr,datas); //返回
if (i==8)
{
printf("\nmain recv data:\n");
printf(" id = %d\n",rid);
printf(" addr = %d\n",addr);
printf(" recr_data = ");
i = 0;
while(i<8)
{
BspBdg0X2(datas[i]);printf(" ");
i++;
}
printf("\n");
}
}
//[测试]主机写数据
void BspRS485MasterWrite_test(u8 id,u8 addr)
{
u8 i;
u8 static datas[] = {1,2,3,4,5,6,7,8};
i = 0;
while(i<8)
{
datas[i] += (i+1);
i++;
}
printf("\n=============master start==============\n");
printf("main write cmd:\n");
printf(" id = %d\n",id);
printf(" addr = %d\n",addr);
printf(" cmd = write\n");
printf(" write_data = ");
BspRS485MasterWrite(id,addr,datas); //发送
i = 0;
while(i<8)
{
BspBdg0X2(datas[i]);printf(" ");
i++;
}
printf("\n");
}
//------主机------
void BspThread1(void * arg)
{
arg = arg;
printf("thread1 run ...\n");
while(1)
{
getchar();
printf(".............................................................");
BspRS485MasterRead_test(2,12); //读取2号,内存0的数据
Sleep(50);
BspRS485MasterWrite_test(2,22);
Sleep(50);
BspRS485MasterRead_test(3,13); //读取3号,内存0的数据
Sleep(50);
BspRS485MasterWrite_test(3,23);
Sleep(50);
BspRS485MasterRead_test(4,14); //读取3号,内存0的数据
Sleep(50);
BspRS485MasterWrite_test(4,24);
Sleep(50);
}
}
//-------------------从机2----------------------------------------------------------------
//[测试]显示接收或发送的消息
void BspRS485Slver_ret_msg_show(u8 i,u8 id,u8 addr,u8*da)
{
if(i!= 0)
{
printf("\nsver respd data:\n");
printf(" id = %d\n",id);
printf(" addr= %d\n",addr);
if(i==8)
{
printf(" cmd = write\n");
printf(" resd_data = ");
}
}
if(i == 8)
{
i = 0;
while(i<8)
{
BspBdg0X2(da[i]);printf(" ");
i++;
}
printf("\n");
}
}
//[测试]显示接收的消息
void BspRS485Slver_recv_msg_show(u8 i,u8 id,u8 addr,u8*da)
{
if(i!= 0)
{
printf("\nsver listd data:\n");
printf(" id = %d\n",id);
printf(" addr= %d\n",addr);
if(i==1)
{
printf(" cmd = read\n");
}
if(i==8)
{
printf(" cmd = write\n");
printf(" recv_data = ");
}
}
if(i == 8)
{
i = 0;
while(i<8)
{
BspBdg0X2(da[i]);printf(" ");
i++;
}
printf("\n");
}
}
RS485_pakg SRpkg;
/* 从机监听数据
参数: id 要监听的id号。 一般是本机ID。[1-127]
返回: *addr 接收内存地址地址。 [1-127]
*datas 当有数据时,接收8byte数据
函数返回
0 0 没有接收到数据
1 有读取命令,地址=addr
8 有写入命令,地址=addr,数据=datas
*/
u8 BspRS485Slver_Listing(u8 id , u8 *addr,u8 *datas)
{
u8 i;
i = BspUart2Recvs__((u8*)&SRpkg.Head,sizeof(SRpkg),2);
if( i == 0 )
{
return 0;
}
if (SRpkg.Head != 0xaa || SRpkg.ID != id )
{
return 0;
}
//校验
if (SRpkg.IshaveDa==1)
{
i = sizeof(SRpkg)-2;
}else
{
i = sizeof(SRpkg)- 10;
}
if(MathXor( (u8*)(&SRpkg.Xor + 1),i) != (char)SRpkg.Xor)
{
return 0;
}
*addr = SRpkg.addr;
//读内存指令
if(SRpkg.IshaveDa==0 && MTpkg.WR == 0)
{
return 1;
}
//写内存指令
if(SRpkg.IshaveDa==1 && MTpkg.WR == 1)
{
for(i=0;i<8;i++)
{
datas[i] = *(&SRpkg.da0 + i);
}
return 8;
}
return 0;
}
/* 从机返回数据给主机
参数: id 从机id [1-127]
addr 从机内存 [1-127]
data 从机要发送的8个数据
*/
u8 BspRS485Slver_respd(u8 id,u8 addr,u8 *datas)
{
//发送数据包
SRpkg.Head =0xaa;
SRpkg.ID = id;
SRpkg.WR = 1;
SRpkg.IshaveDa = 1;
SRpkg.addr = addr;
MathMemCopy(&SRpkg.da0,datas,8);
SRpkg.Xor = MathXor( (u8*)(&SRpkg.Xor + 1),10);
BspUart2Sends__((u8*)&SRpkg.Head,12);
return 0;
}
void BspThread2(void * arg)
{
int i;
char addr;
char da[24]="abcdefgh";
char retda[24]="abcdefgh";
u8 myid = 2;
printf("thread2 run ...\n");
while(1)
{
Sleep(10);
//监听
i = BspRS485Slver_Listing(myid,&addr,da);
BspRS485Slver_recv_msg_show(i,myid,addr,da);
if(i==1)
{
//返回8byte数据
BspRS485Slver_respd(myid,addr,retda);
BspRS485Slver_ret_msg_show(8,myid,addr,retda);
for (i = 0;i<8;i++)
{
retda[i] += 1;
}
}
if(i==8)
{
//接收8byte数据处理
}
}
arg = arg;
}
//-------------------从机3----------------------------------------------------------------
RS485_pakg SR3pkg;
u8 BspRS485Slver3_Listing(u8 id , u8 *addr,u8 *datas)
{
u8 i;
i = BspUart3Recvs__((u8*)&SR3pkg.Head,sizeof(SR3pkg),2);
if( i == 0 )
{
return 0;
}
if (SR3pkg.Head != 0xaa || SR3pkg.ID != id )
{
return 0;
}
//校验
if (SR3pkg.IshaveDa==1)
{
i = sizeof(SR3pkg)-2;
}else
{
i = sizeof(SR3pkg)- 10;
}
if(MathXor( (u8*)(&SR3pkg.Xor + 1),i) != (char)SR3pkg.Xor)
{
return 0;
}
*addr = SR3pkg.addr;
//读内存指令
if(SR3pkg.IshaveDa==0 && MTpkg.WR == 0)
{
return 1;
}
//写内存指令
if(SR3pkg.IshaveDa==1 && MTpkg.WR == 1)
{
for(i=0;i<8;i++)
{
datas[i] = *(&SR3pkg.da0 + i);
}
return 8;
}
return 0;
}
u8 BspRS485Slver3_respd(u8 id,u8 addr,u8 *datas)
{
//发送数据包
SR3pkg.Head =0xaa;
SR3pkg.ID = id;
SR3pkg.WR = 1;
SR3pkg.IshaveDa = 1;
SR3pkg.addr = addr;
MathMemCopy(&SR3pkg.da0,datas,8);
SR3pkg.Xor = MathXor( (u8*)(&SR3pkg.Xor + 1),10);
BspUart3Sends__((u8*)&SR3pkg.Head,12);
return 0;
}
void BspThread3(void * arg)
{
int i;
char addr;
char da[24]="abcdefgh";
char retda[24]="aabbccddeeff";
u8 myid = 3;
printf("thread3 run ...\n");
while(1)
{
Sleep(10);
//监听
i = BspRS485Slver3_Listing(myid,&addr,da);
BspRS485Slver_recv_msg_show(i,myid,addr,da);
if(i==1)
{
//返回8byte数据
BspRS485Slver3_respd(myid,addr,retda);
BspRS485Slver_ret_msg_show(8,myid,addr,retda);
for (i = 0;i<8;i++)
{
retda[i] += 1;
}
}
if(i==8)
{
//接收8byte数据处理
}
}
arg = arg;
}
//-------------------从机4----------------------------------------------------------------
RS485_pakg SR4pkg;
u8 BspRS485Slver4_Listing(u8 id , u8 *addr,u8 *datas)
{
u8 i;
i = BspUart4Recvs__((u8*)&SR4pkg.Head,sizeof(SR4pkg),2);
if( i == 0 )
{
return 0;
}
if (SR4pkg.Head != 0xaa || SR4pkg.ID != id )
{
return 0;
}
if (SR4pkg.IshaveDa==1)
{
i = sizeof(SR4pkg)-2;
}else
{
i = sizeof(SR4pkg)- 10;
}
if(MathXor( (u8*)(&SR4pkg.Xor + 1),i) != (char)SR4pkg.Xor)
{
return 0;
}
*addr = SR4pkg.addr;
if(SR4pkg.IshaveDa==0 && MTpkg.WR == 0)
{
return 1;
}
if(SR4pkg.IshaveDa==1 && MTpkg.WR == 1)
{
for(i=0;i<8;i++)
{
datas[i] = *(&SR4pkg.da0 + i);
}
return 8;
}
return 0;
}
u8 BspRS485Slver4_respd(u8 id,u8 addr,u8 *datas)
{
//发送数据包
SR4pkg.Head =0xaa;
SR4pkg.ID = id;
SR4pkg.WR = 1;
SR4pkg.IshaveDa = 1;
SR4pkg.addr = addr;
MathMemCopy(&SR4pkg.da0,datas,8);
SR4pkg.Xor = MathXor( (u8*)(&SR4pkg.Xor + 1),10);
BspUart4Sends__((u8*)&SR4pkg.Head,12);
return 0;
}
void BspThread4(void * arg)
{
int i;
char addr;
char da[24]="abcdefgh";
char retda[24]="aabbccddeeff";
u8 myid = 4;
printf("thread4 run ...\n");
while(1)
{
Sleep(10);
//监听
i = BspRS485Slver4_Listing(myid,&addr,da);
BspRS485Slver_recv_msg_show(i,myid,addr,da);
if(i==1)
{
//返回8byte数据
BspRS485Slver4_respd(myid,addr,retda);
BspRS485Slver_ret_msg_show(8,myid,addr,retda);
for (i = 0;i<8;i++)
{
retda[i] += 1;
}
}
if(i==8)
{
//接收8byte数据处理
}
}
arg = arg;
}
/****************************************************************************************
模拟通信部分
机制: 任何一个发送信息,其他的都会收到消息。 模拟多机环境
****************************************************************************************/
//****************************Uart1*******************************************************
int BspUart1Init__(void)
{
CharFifoInit(&U1R,U1BUF,U1BUF_LEN);
return 1;
}
UINT32 BspUart1Sends__(u8 *sddata,unsigned int cnt)
{
u32 i = 0;
while(cnt--)
{
CharFifoPut(&U2R,*sddata); //向其他地方发数据
CharFifoPut(&U3R,*sddata);
CharFifoPut(&U4R,*sddata);
sddata++;
}
return i;
}
UINT32 BspUart1Recvs__(u8 *rddata,unsigned int cnt,u32 timeout)
{
u32 i = 0;
char tmp;
while(0 == CharFifoUnmGet(&U1R))
{
//时间到,退出
if(timeout-- == 0)
{
return 0;
}
BspTimeDlyMs(1);
}
while(cnt--)
{
if(1== CharFifoGet(&U1R,&tmp))
{
*rddata++ = tmp;
i++;
}else
{
BspTimeDlyMs(5);
if(CharFifoUnmGet(&U1R)==0)
{
break;
}
}
}
return i;
}
//****************************Uart2*******************************************************
int BspUart2Init__(void)
{
CharFifoInit(&U2R,U2BUF,U2BUF_LEN);
return 1;
}
UINT32 BspUart2Sends__(u8 *sddata,unsigned int cnt)
{
u32 i = 0;
while(cnt--)
{
CharFifoPut(&U1R,*sddata); //向其他地方发数据
CharFifoPut(&U3R,*sddata); //向其他地方发数据
CharFifoPut(&U4R,*sddata); //向其他地方发数据
sddata++;
}
return i;
}
UINT32 BspUart2Recvs__(u8 *rddata,unsigned int cnt,u32 timeout)
{
u32 i = 0;
char tmp;
while(0 == CharFifoUnmGet(&U2R))
{
//时间到,退出
if(timeout-- == 0)
{
return 0;
}
BspTimeDlyMs(1);
}
while(cnt--)
{
if(1== CharFifoGet(&U2R,&tmp))
{
*rddata++ = tmp;
i++;
}else
{
BspTimeDlyMs(5);
if(CharFifoUnmGet(&U2R)==0)
{
break;
}
}
}
return i;
}
//****************************Uart3*******************************************************
int BspUart3Init__(void)
{
CharFifoInit(&U3R,U3BUF,U3BUF_LEN);
return 1;
}
UINT32 BspUart3Sends__(u8 *sddata,unsigned int cnt)
{
u32 i = 0;
while(cnt--)
{
CharFifoPut(&U1R,*sddata); //向其他地方发数据
CharFifoPut(&U2R,*sddata); //向其他地方发数据
CharFifoPut(&U4R,*sddata); //向其他地方发数据
sddata++;
}
return i;
}
UINT32 BspUart3Recvs__(u8 *rddata,unsigned int cnt,u32 timeout)
{
u32 i = 0;
char tmp;
while(0 == CharFifoUnmGet(&U3R))
{
//时间到,退出
if(timeout-- == 0)
{
return 0;
}
BspTimeDlyMs(1);
}
while(cnt--)
{
if(1== CharFifoGet(&U3R,&tmp))
{
*rddata++ = tmp;
i++;
}else
{
BspTimeDlyMs(5);
if(CharFifoUnmGet(&U3R)==0)
{
break;
}
}
}
return i;
}
//****************************Uart4*******************************************************
int BspUart4Init__(void)
{
CharFifoInit(&U4R,U4BUF,U4BUF_LEN);
return 1;
}
UINT32 BspUart4Sends__(u8 *sddata,unsigned int cnt)
{
u32 i = 0;
while(cnt--)
{
CharFifoPut(&U1R,*sddata); //向其他地方发数据
CharFifoPut(&U2R,*sddata); //向其他地方发数据
CharFifoPut(&U3R,*sddata); //向其他地方发数据
sddata++;
}
return i;
}
UINT32 BspUart4Recvs__(u8 *rddata,unsigned int cnt,u32 timeout)
{
u32 i = 0;
char tmp;
while(0 == CharFifoUnmGet(&U4R))
{
//时间到,退出
if(timeout-- == 0)
{
return 0;
}
BspTimeDlyMs(1);
}
while(cnt--)
{
if(1== CharFifoGet(&U4R,&tmp))
{
*rddata++ = tmp;
i++;
}else
{
BspTimeDlyMs(5);
if(CharFifoUnmGet(&U4R)==0)
{
break;
}
}
}
return i;
}