单片机采用51系列 STC12C5A60S2单片机 整个程序源码在附件中。 /****************************** 程序功能: modbus RTU 模式设置读取十六个继电器状态,以及内部保持寄存器的设置读取 硬件测试环境:单片机stc89C52RC十六继电器485接口控制板 通信协议: 晶振:11.0592 波特率:9600 8位数据 1位停止位 偶校验 485通位接口P3.7控制方向端 控制板地址: 修改localAddr(变量) 线圈个数:16个 线圈地址范围:0x0000~0x000F 保持寄存器个数:16个(字节型) 寄存器地址:0x0000~0x000F \\******************************\\ 功能码简介: 02:读取单个线圈状态 03:读取多个保持寄存器 05:设置单个线圈状态 06:设置单个寄存器值 0F:设置多个线圈 10:设置多个保持寄存器 *******************************/ #include "hader\\main.h" uint32 dwTickCount,dwIntTick; //时钟 uint8 idata sendBuf[32],receBuf[16]; //发送接收缓冲区 uint8 idata checkoutError; // ==2 偶校验错 uint8 idata receTimeOut; //接收超时 uint8 idata c10ms; //10ms 计时 uint8 idata c200ms; bit b1ms,bt1ms,b10ms,bt10ms,b100ms,bt100ms; //定时标志位
//定时处理 void timeProc(void) { b1ms = 0; if(bt1ms) //如果1ms到 { bt1ms = 0; b1ms = 1; if(receTimeOut>0) //如果接收超时值>0 { receTimeOut--; //接收超时-1(1ms减1次) if(receTimeOut==0 && receCount>0) //判断通讯接收是否超时 { // b485Send = 0; //将485置为接收状态 receCount = 0; //将接收地址偏移寄存器清零 checkoutError = 0; } } } } // void TimerProc(void) //初始化 void initInt(void) { SCON = 0xd0; TMOD = 0x21; PCON = 0; TH0 = TIMER_HIGHT; TL0 = TIMER_LOW; TH1= 0xfd; TL1 = 0xfd; //波特率 9600
TR0 = 1; TR1=1; ET0 = 1; ES = 1; EA = 1;
//串口2设置 S2CON = 0xd0; //方式1,9位数据,波特率不可变 S2TB8 偶校验位 BRT=0XFD; //设置波特率9600 AUXR=0x10; //启动串口1波特率发生器 IP=0x00; //优先级默认 //开串口1中断 IE2=0x01; //开串口2中断 } //初始化 void initProg(void) {
P4SW|=0x20; //配置P4.5为IO口 P4M0|=0x10; //配置P4.4为IO口 P4M1|=0x10; P0=P1=P2=P3=0xff; P4|=0x30; initInt(); //初始化定时器 // b485Send = 0; } //上电时读取上次线圈状态,并设置 void forceMultipleCoils1() { uint8 tempAddr; uint8 i,k; uint8 Data; uint8 exit = 0; for(k=0;k<4;k++) { switch(k) { case 0:Data=coilreg1; break; case 1:Data=coilreg2; break; case 2:Data=coilreg3; break; case 3:Data=coilreg4; break; } for(i=0;i<8;i++) { if( Data &0x01==1) setCoilVal(tempAddr,0); else setCoilVal(tempAddr,1);
Data=Data>>1; tempAddr++; if(tempAddr >=32) { exit = 1; break; } } if(exit==1) break; } } void main(void) {
initProg(); localAddr=EEPROMReadByte(0); //从EERPOM的相对0地址读取数据 coilreg1=EEPROMReadByte(1); coilreg2=EEPROMReadByte(2); coilreg3=EEPROMReadByte(3); coilreg4=EEPROMReadByte(4); forceMultipleCoils1(); if(localAddr>=10) { localAddr=1; EEPROMSectorErase(0); //从EEPROM的相对0地址扇区擦除 EEPROMWriteByte(0,localAddr); EEPROMWriteByte(1,coilreg1); EEPROMWriteByte(2,coilreg2); EEPROMWriteByte(3,coilreg1); EEPROMWriteByte(4,coilreg2); } WDT_CONTR =0x32; //大概284.4ms while(1) { timeProc(); checkComm0Modbus(); } } //定时器0 1ms 中断 void timer0IntProc() interrupt 1 { TL0 = TIMER_LOW; TH0 = TIMER_HIGHT; dwIntTick++; bt1ms = 1; c10ms++; c200ms++; if(c10ms >= 10) { c10ms = 0; //20ms计时器清零 bt10ms = 1; WDT_CONTR =0x32; // } } // void Timer0IntProc() // 串行中断1程序 void commIntProc() interrupt 4 { if(TI) { TI = 0; if(sendPosi < sendCount) //如果发送位置小于发送计数,那么继续发送 { sendPosi++; ACC = sendBuf[sendPosi]; TB8 = P; //加上校验位 SBUF = sendBuf[sendPosi]; } else //否则发送完毕,置接收状态 { // b485Send = 0; //发送完后将485置于接收状态 receCount = 0; //清接收地址偏移寄存器 checkoutError = 0; } } else if(RI) { RI = 0; receTimeOut = 10; //通讯超时值 receBuf[receCount] = SBUF; ACC = receBuf[receCount]; if(P != RB8) checkoutError = 2; //偶校验出错 receCount++; //接收地址偏移寄存器加1 receCount &= 0x0f; //最多一次只能接收16个字节 } } // void CommIntProc() //串口2中断 void uart2_isr() interrupt 8 {
if( S2CON & 0x02 ) { S2CON &= ~0x02; if(sendPosi<receCount) //如果发送位置小于发送计数,那么继续发送 { sendPosi++; ACC = receBuf[sendPosi]; if(P) S2CON|=0x08; // 7 6 5 4 3 2 1 0 Reset Value //sfr S2CON = 0x9A; //S2 Control S2SM0 S2SM1 S2SM2 S2REN S2TB8 S2RB8 S2TI S2RI 00000000B else S2CON&=0xf7; S2BUF =receBuf[sendPosi]; } else //否则发送完毕,置接收状态 { // b485Send = 0; //发送完后将485置于接收状态 receCount = 0; //清接收地址偏移寄存器 checkoutError = 0; } } else if( S2CON & 0x01)//接收 { S2CON &= ~0x01; receTimeOut = 10; //通讯超时值 receBuf[receCount] =S2BUF; ACC = receBuf[receCount]; // if(P != RB8) // checkoutError = 2; //偶校验出错 receCount++; //接收地址偏移寄存器加1 receCount &= 0x0f; //最多一次只能接收16个字节 } }
|