亚洲春色中文字幕久久久-三上亚,91精品国产亚一区二区三区,久久久九色综合亚洲成色777,涩涩视频下载,国产午夜亚洲精品午夜鲁丝片,国产精品A一区二区三区腾讯导航,影音先锋色情AV在线看片,蜜臀国产在线视频,极品少妇高潮啪啪无码吴梦梦 ,精品人妻无码一区二区三区手机版

標(biāo)題: stm32庫(kù)函數(shù)編寫(xiě)的modbus源代碼 [打印本頁(yè)]

作者: 51黑ren    時(shí)間: 2015-12-27 06:10
標(biāo)題: stm32庫(kù)函數(shù)編寫(xiě)的modbus源代碼
說(shuō)在前面的話(huà):
1. 請(qǐng)勿盲目抄襲。這個(gè)協(xié)議使用了一個(gè)定時(shí)器,所以在別處請(qǐng)不要再使用,如果定時(shí)器不夠用,可以做虛擬定時(shí)器。也就是采用一個(gè)物理的定時(shí)器產(chǎn)生時(shí)基。在這個(gè)定時(shí)器的中斷函數(shù)中可以給相應(yīng)的多個(gè)定時(shí)器自加1.每個(gè)虛擬定時(shí)器可以用兩個(gè)變量分別控制打開(kāi)關(guān)閉,和計(jì)時(shí)。這個(gè)已經(jīng)試驗(yàn)通過(guò)了可行的。其實(shí)就跟我們使用物理的定時(shí)器一樣,只不過(guò)物理的定時(shí)器是用晶振產(chǎn)生時(shí)基。
2. 這段代碼已經(jīng)調(diào)試通過(guò)了,也硬件試驗(yàn)過(guò),沒(méi)有問(wèn)題,如果你出現(xiàn)問(wèn)題了,看看你在主函數(shù)的的各種基本配置有沒(méi)有完成。如果要使用06和10號(hào)功能,你還需要在主函數(shù)中建立一個(gè)100個(gè)元素的數(shù)組,每個(gè)元素是16位。
3. 寫(xiě)這個(gè)文檔的時(shí)候,這個(gè)協(xié)議已經(jīng)是半年前完成的了。所以有些東西記得不是很清楚了,如果說(shuō)錯(cuò)了,請(qǐng)以實(shí)際為準(zhǔn)。只是不想讓這份代碼死在電腦中了,所以才想起來(lái)要拿出來(lái)分享,支持開(kāi)源精神。
4. 如果實(shí)在實(shí)在是沒(méi)有弄出來(lái),請(qǐng)聯(lián)系我,可以共同交流,我的QQ:810663503 電話(huà):18046771801
#include"stm32f10x.h"



//modbus用通訊參數(shù)
u8 Tim_Out;//大于3.5個(gè)字符時(shí)間,保守取3ms (波特率9600的時(shí)候大約2點(diǎn)幾毫秒)
u8 Rcv_Complete;//一幀是否已經(jīng)接受完成
u8 Send_Complete;//一幀是否已經(jīng)發(fā)送完成
u8 Com_busy;//通訊繁忙,表示上一幀還未處理結(jié)束
u8 Rcv_Buffer[210];//用來(lái)存放接收到的完整的一幀數(shù)據(jù)(第一個(gè)字節(jié)用來(lái)存放接收到的有效字節(jié)數(shù),也就是數(shù)組中的有效字節(jié)數(shù)) 
u8 Send_Buffer[210];//用來(lái)存放待發(fā)送的完整的一幀數(shù)據(jù)(第一個(gè)字節(jié)用來(lái)存放待發(fā)送的有效字節(jié)數(shù),也就是數(shù)組中的有效字節(jié)數(shù))
u8 Rcv_Data;//用來(lái)存放接收的一個(gè)字節(jié)
u8 Send_Data;//用來(lái)存放要發(fā)送的一字節(jié)
u8 Mod_Id;//用來(lái)標(biāo)志作為從站的站號(hào)
u8 Rcv_Num;//用來(lái)表示接收的一幀的有效字節(jié)數(shù)(從功能碼到CRC校驗(yàn))
u8 Send_Num;//用來(lái)表示待發(fā)送的一幀的字節(jié)數(shù)
u8 *PointToRcvBuf;//用來(lái)指向接收的數(shù)據(jù)緩存
u8 *PointToSendBuf;//用來(lái)指向帶發(fā)送的數(shù)據(jù)緩存
u8 Comu_Busy;//用來(lái)表示能否接收下一幀數(shù)據(jù)
u8 HaveMes;
extern u16 HoldReg[100];


//CRC校驗(yàn)查表用參數(shù)

static u8 auchCRCHi[] = {
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,
0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,
0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,
0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,
0x81,0x40,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,
0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,
0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,
0x80,0x41,0x00,0xC1,0x81,0x40
} ;

static u8 auchCRCLo[] = {
0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,
0x07,0xC7,0x05,0xC5,0xC4,0x04,0xCC,0x0C,0x0D,0xCD,
0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,
0x08,0xC8,0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,
0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,0x14,0xD4,
0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,
0x11,0xD1,0xD0,0x10,0xF0,0x30,0x31,0xF1,0x33,0xF3,
0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,
0x3B,0xFB,0x39,0xF9,0xF8,0x38,0x28,0xE8,0xE9,0x29,
0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,
0xEC,0x2C,0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,
0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,0xA0,0x60,
0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,
0xA5,0x65,0x64,0xA4,0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,
0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,
0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,0xB4,0x74,0x75,0xB5,
0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,
0x70,0xB0,0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,
0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9C,0x5C,
0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,
0x99,0x59,0x58,0x98,0x88,0x48,0x49,0x89,0x4B,0x8B,
0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,
0x43,0x83,0x41,0x81,0x80,0x40
} ;

//聲明modbus的函數(shù)
void ModInit(u8 Id);//用于Modbus初始化,參數(shù)Id為站號(hào)(1-255)
void ModRcv(void);//用于modbus信息接收
void ModSend(void);//用于modbus信息接收
void MessageHandle(u8 *pointer_in,u8 *pointer_out);//處理收到的信息幀
void ReadOutputBit(u8 *pointer_1,u8 *pointer_2);//讀線(xiàn)圈
void ReadInputBit(u8 *pointer_1,u8 *pointer_2);//讀輸入位
void ReadHoldingReg(u8 *pointer_1,u8 *pointer_2);//讀保持寄存器
void ReadInputReg(u8 *pointer_1,u8 *pointer_2);//讀輸入寄存器
void ForceSingleCoil(u8 *pointer_1,u8 *pointer_2);//強(qiáng)制單個(gè)線(xiàn)圈
void PresetSingleReg(u8 *pointer_1,u8 *pointer_2);//預(yù)制單個(gè)寄存器
void ForceMulCoil(u8 *pointer_1,u8 *pointer_2);//強(qiáng)制多個(gè)線(xiàn)圈
void PresetMulReg(u8 *pointer_1,u8 *pointer_2);//預(yù)制多個(gè)寄存器
void ErrorHandle(u8 Mode,u8 *Pointer);//錯(cuò)誤信息幀處理
u16 CRC16(u8 *puchMsgg,u8 usDataLen);//用于計(jì)算CRC校驗(yàn)碼





void ModInit(u8 Id)
{
//modbus參數(shù)初始化
PointToRcvBuf=Rcv_Buffer;
PointToSendBuf=Send_Buffer;
Send_Num=1;//發(fā)送的數(shù)據(jù)順序(輸出數(shù)組的第幾個(gè)數(shù))
Mod_Id=Id;//站號(hào)設(shè)置
Rcv_Buffer[1]=Mod_Id;
Send_Buffer[1]=Mod_Id;
Comu_Busy=0;
}


void ModRcv(void)
{
HaveMes=1;//表示接收到了信息
Rcv_Data=USART_ReceiveData(USART1);
if(Comu_Busy!=1)//如果不忙,可以接收下一幀信息
{
TIM_Cmd(TIM2, DISABLE);
TIM_SetCounter(TIM2,0);
if((Tim_Out!=0)&&(Rcv_Data==Mod_Id))//如果間隔時(shí)間超過(guò)了3.5個(gè)字符,同時(shí)接受的字節(jié)和自己的站號(hào)一致,則認(rèn)為接收開(kāi)始
{
Rcv_Complete=0;//表示數(shù)據(jù)幀接收開(kāi)始
Rcv_Num=0;//接收數(shù)據(jù)個(gè)數(shù)初始化
Rcv_Num++;//同時(shí)個(gè)數(shù)加一
}
if((0==Tim_Out)&&(0==Rcv_Complete))//如果處于接收一幀的正常過(guò)程中
{
if(Rcv_Num<100)
{
Rcv_Buffer[Rcv_Num+1]=Rcv_Data;//將數(shù)據(jù)放入接收數(shù)組中
Rcv_Num++;//同時(shí)個(gè)數(shù)加一
}
else
{
Rcv_Complete=1;
Comu_Busy=1;
Rcv_Buffer[0]=Rcv_Num;
*(PointToSendBuf+2)=*(PointToRcvBuf+2);//獲取功能碼
ErrorHandle(6,PointToSendBuf);//表示超出了字節(jié)數(shù)(從機(jī)設(shè)備忙碌)
Rcv_Num=0;
}
}
Tim_Out=0;
TIM_Cmd(TIM2, ENABLE);//開(kāi)啟4.5ms計(jì)時(shí)(三個(gè)半字符的保守估計(jì))
}

}


void ModSend(void)
{
Send_Data=*(PointToSendBuf+Send_Num);
USART_SendData(USART1,Send_Data);
Send_Num++;
if(Send_Num>(*PointToSendBuf))//發(fā)送已經(jīng)完成
{
Comu_Busy=0;
*PointToSendBuf=0;
Rcv_Num=0;
Send_Num=1;
//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, DISABLE);//關(guān)閉數(shù)據(jù)發(fā)送中斷
}
}


void TIM2_IRQHandler(void) 
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //檢查指定的TIM中斷發(fā)生與否:TIM 中斷源 
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx的中斷待處理位:TIM 中斷源
Tim_Out=1;
TIM_Cmd(TIM2,DISABLE);
TIM_SetCounter(TIM2,0);
Rcv_Complete=1;
Rcv_Buffer[0]=Rcv_Num;

函數(shù)輸入:兩個(gè)指針,pointer_1指向用來(lái)存放輸入信息幀的數(shù)組,
pointer_2用來(lái)指向存放輸出信息幀的數(shù)組(兩個(gè)數(shù)組的第一個(gè)元素都用來(lái)存放信息幀的有效字節(jié)個(gè)數(shù))
后面的元素按照Modbus協(xié)議組織。 
函數(shù)輸出:無(wú)。 */

void ForceMulCoil(u8 *pointer_1,u8 *pointer_2)//pointer_1用作輸入,pointer_2用作輸出
{
u16 Address=0;//待強(qiáng)制線(xiàn)圈起始地址(GPIO_X,X為C,D兩個(gè)端口,每個(gè)端口16位,對(duì)應(yīng)地址0——31)
u16 Num=0;//要強(qiáng)制的線(xiàn)圈個(gè)數(shù)
u8 ByteCount;//命令值的字節(jié)個(gè)數(shù)
u32 CommandValue;//命令的數(shù)值,有效的每個(gè)位用來(lái)置位或者復(fù)位指定地址的線(xiàn)圈
u32 PortTemp;//用來(lái)存放從端口取過(guò)來(lái)的數(shù)據(jù)
u32 CalTemp;//臨時(shí)計(jì)算用
u16 ReadData=0;//用來(lái)臨時(shí)存放從端口讀來(lái)的數(shù)據(jù)
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值
u8 CountTemp;//計(jì)算實(shí)際需要的命令字節(jié)數(shù)

Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到線(xiàn)圈地址
Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到線(xiàn)圈數(shù)量
ByteCount= *(pointer_1+7);//表示命令值的字節(jié)數(shù)
CountTemp=(u8)(Num/8);
if(Num%8!=0)
CountTemp++;
*(pointer_2+2)=0x0F;//第三個(gè)字節(jié)為功能碼


if((*(pointer_1)==9+ByteCount)&&ByteCount>0&&ByteCount<=4&&CountTemp==ByteCount)//如果接收到的字節(jié)數(shù)不是預(yù)定的個(gè)數(shù),或者命令字節(jié)數(shù)超出允許范圍就是一個(gè)錯(cuò)誤幀
{

if(Address<32) //只要地址小于32,就是合法地址
{
if(Address+Num<=32&&Num>0) //只要地址加數(shù)量大于0小于32,就是合法數(shù)量
{
//用于for循環(huán)
u8 i;
u8 j;

//把命令值做一些處理,存入CommandValue
CommandValue=0;
for(i=0,j=ByteCount;j>0;i++,j--)
{
CommandValue|=((u32)*(pointer_1+8+i))<<8*i;//將輸入數(shù)據(jù)緩存中的數(shù)據(jù)存入CommandValue
}
CommandValue=CommandValue<<Address;//移動(dòng)到對(duì)應(yīng)起始位位置

*(pointer_2)=1+1+2+2+2;//有效字節(jié)個(gè)數(shù)等于叢機(jī)地址+功能碼+線(xiàn)圈起始地址+線(xiàn)圈數(shù)量+CRC校驗(yàn)
*(pointer_2+3)=*(pointer_1+3);//將地址值寫(xiě)入輸出的寄存器中
*(pointer_2+4)=*(pointer_1+4);
*(pointer_2+5)=*(pointer_1+5);//將線(xiàn)圈數(shù)量值寫(xiě)入輸出的寄存器中
*(pointer_2+6)=*(pointer_1+6);

//將端口C和D的數(shù)據(jù)預(yù)先讀入到臨時(shí)的數(shù)據(jù)緩存中
ReadData=GPIO_ReadOutputData(GPIOD);
PortTemp=(u32)(ReadData);
PortTemp=PortTemp<<16;
ReadData=GPIO_ReadOutputData(GPIOC);
PortTemp=PortTemp|(u32)(ReadData);

//將需要讀出來(lái)的數(shù)據(jù)按要求處理
CalTemp=0xFFFFFFFF<<32-Num;
CalTemp=CalTemp>>32-Num-Address;
CalTemp=~CalTemp;
PortTemp&=CalTemp;
PortTemp|=CommandValue;

//再將數(shù)據(jù)寫(xiě)入
GPIO_Write(GPIOC,(u16)(PortTemp&0x0000FFFF));
GPIO_Write(GPIOD,(u16)(PortTemp>>16));

//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(pointer_2+1,*pointer_2-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);
*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷

}
else
{
ErrorHandle(3,pointer_2);//錯(cuò)誤讀取數(shù)量
}
}
else
{
ErrorHandle(2,pointer_2);//錯(cuò)誤起始地址
}
}
else
{
Comu_Busy=0;
}
}




void PresetMulReg(u8 *pointer_1,u8 *pointer_2)//pointer_1用作輸入,pointer_2用作輸出
{
u16 Address=0;//待預(yù)制寄存器的起始地址(HoldReg[i],i為0-99對(duì)應(yīng)地址從0到99)
u16 Num=0;//要預(yù)制的寄存器數(shù)量
u8 ByteCount;//預(yù)制值的字節(jié)個(gè)數(shù)
u16 PresetValue=0;//預(yù)制數(shù)值
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值


Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到寄存器地址
Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到待預(yù)制寄存器數(shù)量
*(pointer_2+2)=0x10;//第三個(gè)字節(jié)為功能碼
ByteCount= *(pointer_1+7);//表示命令值的字節(jié)數(shù)

if((*(pointer_1)==9+ByteCount)&&ByteCount>0&&ByteCount<=200&&ByteCount==(u8)(Num*2))//如果接收到的字節(jié)數(shù)不是預(yù)定的個(gè)數(shù),或者命令字節(jié)數(shù)超出允許范圍就是一個(gè)錯(cuò)誤幀
{

if(Address<100) //只要地址小于100,就是合法地址
{

if(Address+Num<=100&&Num>0) //只要地址加數(shù)量大于0小于100,就是合法數(shù)量
{
//用于for循環(huán)
u8 i;
u8 j;

*(pointer_2)=1+1+2+2+2;//有效字節(jié)個(gè)數(shù)等于叢機(jī)地址+功能碼+寄存器地址+寄存器數(shù)量+CRC校驗(yàn)
*(pointer_2+3)=*(pointer_1+3);//將地址值寫(xiě)入輸出的寄存器中
*(pointer_2+4)=*(pointer_1+4);
*(pointer_2+5)=*(pointer_1+5);//將數(shù)量寫(xiě)入輸出寄存器中
*(pointer_2+6)=*(pointer_1+6);

for(i=0,j=0;i 
{
PresetValue=(u16)(*(pointer_1+8+j))*256+(*(pointer_1+9+j));//先得到預(yù)制值
HoldReg[Address+i]=PresetValue;//將預(yù)制值寫(xiě)入保持寄存器
}


//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(pointer_2+1,*pointer_2-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);
*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷

}
else
{
ErrorHandle(3,pointer_2);//錯(cuò)誤讀取數(shù)量
}

}
else
{
ErrorHandle(2,pointer_2);//錯(cuò)誤起始地址
}
}
else
{
Comu_Busy=0;
}
}




void ErrorHandle(u8 Mode,u8 *Pointer)
{
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值

HaveMes=0;//清除信息位
TIM_Cmd(TIM2,DISABLE);
TIM_SetCounter(TIM3,0);
Rcv_Complete=1;
Comu_Busy=1;
Rcv_Buffer[0]=Rcv_Num;
switch(Mode)
{
case 1:*(Pointer+3)=0x01;//錯(cuò)誤功能碼
break; 
case 2:*(Pointer+3)=0x02;//錯(cuò)誤地址
break;
case 3:*(Pointer+3)=0x03;//錯(cuò)誤數(shù)據(jù)
break;
case 6:*(Pointer+3)=0x06;//從設(shè)備忙
break;
}
*Pointer=0x05;//輸出寄存器有效數(shù)據(jù)個(gè)數(shù)
*(Pointer+2)|=0x80;//功能碼最高位置一
//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(Pointer+1,*Pointer-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(Pointer+(*Pointer-1))=(u8)(SendKey>>8);
*(Pointer+(*Pointer))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷 
}

函數(shù)輸入:兩個(gè)指針,pointer_1指向用來(lái)存放輸入信息幀的數(shù)組,
pointer_2用來(lái)指向存放輸出信息幀的數(shù)組(兩個(gè)數(shù)組的第一個(gè)元素都用來(lái)存放信息幀的有效字節(jié)個(gè)數(shù))
后面的元素按照Modbus協(xié)議組織。 
函數(shù)輸出:無(wú)。 */

void ForceMulCoil(u8 *pointer_1,u8 *pointer_2)//pointer_1用作輸入,pointer_2用作輸出
{
u16 Address=0;//待強(qiáng)制線(xiàn)圈起始地址(GPIO_X,X為C,D兩個(gè)端口,每個(gè)端口16位,對(duì)應(yīng)地址0——31)
u16 Num=0;//要強(qiáng)制的線(xiàn)圈個(gè)數(shù)
u8 ByteCount;//命令值的字節(jié)個(gè)數(shù)
u32 CommandValue;//命令的數(shù)值,有效的每個(gè)位用來(lái)置位或者復(fù)位指定地址的線(xiàn)圈
u32 PortTemp;//用來(lái)存放從端口取過(guò)來(lái)的數(shù)據(jù)
u32 CalTemp;//臨時(shí)計(jì)算用
u16 ReadData=0;//用來(lái)臨時(shí)存放從端口讀來(lái)的數(shù)據(jù)
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值
u8 CountTemp;//計(jì)算實(shí)際需要的命令字節(jié)數(shù)

Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到線(xiàn)圈地址
Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到線(xiàn)圈數(shù)量
ByteCount= *(pointer_1+7);//表示命令值的字節(jié)數(shù)
CountTemp=(u8)(Num/8);
if(Num%8!=0)
CountTemp++;
*(pointer_2+2)=0x0F;//第三個(gè)字節(jié)為功能碼


if((*(pointer_1)==9+ByteCount)&&ByteCount>0&&ByteCount<=4&&CountTemp==ByteCount)//如果接收到的字節(jié)數(shù)不是預(yù)定的個(gè)數(shù),或者命令字節(jié)數(shù)超出允許范圍就是一個(gè)錯(cuò)誤幀
{

if(Address<32) //只要地址小于32,就是合法地址
{
if(Address+Num<=32&&Num>0) //只要地址加數(shù)量大于0小于32,就是合法數(shù)量
{
//用于for循環(huán)
u8 i;
u8 j;

//把命令值做一些處理,存入CommandValue
CommandValue=0;
for(i=0,j=ByteCount;j>0;i++,j--)
{
CommandValue|=((u32)*(pointer_1+8+i))<<8*i;//將輸入數(shù)據(jù)緩存中的數(shù)據(jù)存入CommandValue
}
CommandValue=CommandValue<<Address;//移動(dòng)到對(duì)應(yīng)起始位位置

*(pointer_2)=1+1+2+2+2;//有效字節(jié)個(gè)數(shù)等于叢機(jī)地址+功能碼+線(xiàn)圈起始地址+線(xiàn)圈數(shù)量+CRC校驗(yàn)
*(pointer_2+3)=*(pointer_1+3);//將地址值寫(xiě)入輸出的寄存器中
*(pointer_2+4)=*(pointer_1+4);
*(pointer_2+5)=*(pointer_1+5);//將線(xiàn)圈數(shù)量值寫(xiě)入輸出的寄存器中
*(pointer_2+6)=*(pointer_1+6);

//將端口C和D的數(shù)據(jù)預(yù)先讀入到臨時(shí)的數(shù)據(jù)緩存中
ReadData=GPIO_ReadOutputData(GPIOD);
PortTemp=(u32)(ReadData);
PortTemp=PortTemp<<16;
ReadData=GPIO_ReadOutputData(GPIOC);
PortTemp=PortTemp|(u32)(ReadData);

//將需要讀出來(lái)的數(shù)據(jù)按要求處理
CalTemp=0xFFFFFFFF<<32-Num;
CalTemp=CalTemp>>32-Num-Address;
CalTemp=~CalTemp;
PortTemp&=CalTemp;
PortTemp|=CommandValue;

//再將數(shù)據(jù)寫(xiě)入
GPIO_Write(GPIOC,(u16)(PortTemp&0x0000FFFF));
GPIO_Write(GPIOD,(u16)(PortTemp>>16));

//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(pointer_2+1,*pointer_2-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);
*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷

}
else
{
ErrorHandle(3,pointer_2);//錯(cuò)誤讀取數(shù)量
}
}
else
{
ErrorHandle(2,pointer_2);//錯(cuò)誤起始地址
}
}
else
{
Comu_Busy=0;
}
}




void PresetMulReg(u8 *pointer_1,u8 *pointer_2)//pointer_1用作輸入,pointer_2用作輸出
{
u16 Address=0;//待預(yù)制寄存器的起始地址(HoldReg[i],i為0-99對(duì)應(yīng)地址從0到99)
u16 Num=0;//要預(yù)制的寄存器數(shù)量
u8 ByteCount;//預(yù)制值的字節(jié)個(gè)數(shù)
u16 PresetValue=0;//預(yù)制數(shù)值
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值


Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到寄存器地址
Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到待預(yù)制寄存器數(shù)量
*(pointer_2+2)=0x10;//第三個(gè)字節(jié)為功能碼
ByteCount= *(pointer_1+7);//表示命令值的字節(jié)數(shù)

if((*(pointer_1)==9+ByteCount)&&ByteCount>0&&ByteCount<=200&&ByteCount==(u8)(Num*2))//如果接收到的字節(jié)數(shù)不是預(yù)定的個(gè)數(shù),或者命令字節(jié)數(shù)超出允許范圍就是一個(gè)錯(cuò)誤幀
{

if(Address<100) //只要地址小于100,就是合法地址
{

if(Address+Num<=100&&Num>0) //只要地址加數(shù)量大于0小于100,就是合法數(shù)量
{
//用于for循環(huán)
u8 i;
u8 j;

*(pointer_2)=1+1+2+2+2;//有效字節(jié)個(gè)數(shù)等于叢機(jī)地址+功能碼+寄存器地址+寄存器數(shù)量+CRC校驗(yàn)
*(pointer_2+3)=*(pointer_1+3);//將地址值寫(xiě)入輸出的寄存器中
*(pointer_2+4)=*(pointer_1+4);
*(pointer_2+5)=*(pointer_1+5);//將數(shù)量寫(xiě)入輸出寄存器中
*(pointer_2+6)=*(pointer_1+6);

for(i=0,j=0;i 
{
PresetValue=(u16)(*(pointer_1+8+j))*256+(*(pointer_1+9+j));//先得到預(yù)制值
HoldReg[Address+i]=PresetValue;//將預(yù)制值寫(xiě)入保持寄存器
}


//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(pointer_2+1,*pointer_2-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);
*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷

}
else
{
ErrorHandle(3,pointer_2);//錯(cuò)誤讀取數(shù)量
}

}
else
{
ErrorHandle(2,pointer_2);//錯(cuò)誤起始地址
}
}
else
{
Comu_Busy=0;
}
}




void ErrorHandle(u8 Mode,u8 *Pointer)
{
u16 SendKey;//要發(fā)送數(shù)據(jù)的校驗(yàn)值

HaveMes=0;//清除信息位
TIM_Cmd(TIM2,DISABLE);
TIM_SetCounter(TIM3,0);
Rcv_Complete=1;
Comu_Busy=1;
Rcv_Buffer[0]=Rcv_Num;
switch(Mode)
{
case 1:*(Pointer+3)=0x01;//錯(cuò)誤功能碼
break; 
case 2:*(Pointer+3)=0x02;//錯(cuò)誤地址
break;
case 3:*(Pointer+3)=0x03;//錯(cuò)誤數(shù)據(jù)
break;
case 6:*(Pointer+3)=0x06;//從設(shè)備忙
break;
}
*Pointer=0x05;//輸出寄存器有效數(shù)據(jù)個(gè)數(shù)
*(Pointer+2)|=0x80;//功能碼最高位置一
//寫(xiě)入校驗(yàn)碼
SendKey=CRC16(Pointer+1,*Pointer-2);
//將計(jì)算出來(lái)的校驗(yàn)碼裝入輸出數(shù)據(jù)緩存中
*(Pointer+(*Pointer-1))=(u8)(SendKey>>8);
*(Pointer+(*Pointer))=(u8)(SendKey&0x00FF);

//啟動(dòng)數(shù)據(jù)發(fā)送
USART_ITConfig(USART1, USART_IT_TC, ENABLE);//開(kāi)啟數(shù)據(jù)發(fā)送中斷 
}


作者: 奔跑的阿蛋    時(shí)間: 2016-12-7 17:06
樓主   好人,愛(ài)死你了
作者: ahljj    時(shí)間: 2017-1-28 00:15
版主厲害
作者: guoguo0312    時(shí)間: 2017-5-4 21:13
感謝樓主!
作者: swap1    時(shí)間: 2018-7-19 17:05
學(xué)習(xí)了
作者: shbion    時(shí)間: 2019-1-27 21:55
好人一生平安
作者: shbion    時(shí)間: 2019-1-28 09:49
厲害了,謝謝分享
作者: shbion    時(shí)間: 2019-1-28 10:33
厲害了,謝謝分享厲害了,謝謝分享厲害了,謝謝分享
作者: hkf145    時(shí)間: 2019-1-31 10:43
謝謝樓主分享
作者: YZM168    時(shí)間: 2019-5-3 21:56
代碼有點(diǎn)問(wèn)題 673221454@QQ.COM,可以將源代碼給我嗎
作者: wis98    時(shí)間: 2019-5-7 15:34
版主厲害
作者: colinh    時(shí)間: 2019-5-10 14:54
做個(gè)標(biāo)記,項(xiàng)目中有modbus的部分,可以參考參考,感謝樓主
作者: zky2003    時(shí)間: 2019-5-10 18:35
強(qiáng),無(wú)私分享
作者: BATTERYOPTION    時(shí)間: 2019-5-12 17:23
感謝樓主!
作者: BATTERYOPTION    時(shí)間: 2019-5-12 17:24
zky2003 發(fā)表于 2019-5-10 18:35
強(qiáng),無(wú)私分享

感謝樓主

作者: irisice008    時(shí)間: 2019-5-17 20:54
感謝樓主分享
作者: 88889527    時(shí)間: 2019-10-24 00:25
謝謝樓主,很受用
作者: lx5831    時(shí)間: 2019-11-19 15:45
謝謝分享
作者: 用戶(hù)名小黑客    時(shí)間: 2020-4-10 14:58
代碼問(wèn)題太多啊!!!!




歡迎光臨 (http://www.denmoz.com/bbs/) Powered by Discuz! X3.1