// Modbus RTU master demo // // For use with 4.3" iSMART TFT and red-y GSC series flow controller // For product details visit http://www.voegtlin.com/english/products/gas/mass_flow_meters_smart_series.html // // Reads serial number, flow rate and temperature every 500ms // // Scheme :- // After each response the next request is sent. After each response is received the // relavant data is updated. If no response is received the field is set to '-' and the next // request is sent. // The page is only refreshed once, after the last response is received. // // Request serial number, receive response // Request flow rate, receive response // Request temperature, receive response // Load timer to read next data set lib(fnt3, "sdhc/asc_48.fnt"); lib(fnt4, "sdhc/asc_32.fnt"); setup(rs4) { baud = 9600; parity = N; flow = N; encode = sd; duplex = F; rxi = Y; txi = Y; } var(csum, 0, U16); var(csumH, 0, U8); var(csumL, 0, U8); var(csumHp, 0, U8); var(csumLp, 0, U8); var(temp, 0, U8); var(address, 0, U8); var(function, 0, U8); var(register, 0, U16); var(length, 0, U16); var(rxbuffer, 0, U8, 16); var(txbuffer, 0, U8, 8); var(rxlen, 0, U8); var(rxptr, 0, U8); var(tval, 0, U32); var(fval, 0.0, FLT1); var(getstage, 0, U8); var(setflow, 1000, U32); var(temptxt, "", TXT); var(dat, 0, U32); var(pollinterval, 500, U16); var(msgtimeout, 250, U16); style(stPage, page) { back = black; } style(stText1l, text) { font = fnt4; col = white; currel = LC; } style(stText1r, text) { font = fnt4; col = white; currel = RC; } style(stText1c, text) { font = fnt4; col = white; currel = CC; } style(stText2l, text) { font = fnt3; col = white; currel = LC; } style(stText2r, text) { font = fnt3; col = white; currel = RC; } style(stDraw1, Draw) { back = \\444444; col=white; type = Box; curRel = TL; } int(mytimer1, TIMER0, getdata); int(mytimer2, TIMER1, timeout); int(rx, RS4RXC, rxfunc); func(sendreq) { load(txbuffer.0, address); load(txbuffer.1, function); calc(txbuffer.2, register, 256, "/"); calc(txbuffer.3, register, 256, "%"); calc(txbuffer.4, length, 256, "/"); calc(txbuffer.5, length, 256, "%"); calc(csum, txbuffer, 6, "", "CRC16"); calc(csumH, csum, 256, "/"); calc(csumL, csum, 256, "%"); load(txbuffer.6, csumL); load(txbuffer.7, csumH); load(rs4, txbuffer); load(TIMER1, msgtimeout, 1); } func(getdata) { run(getserial); } func(getserial) { load(address, 3); load(function, 3); load(register, 30); load(length, 2); load(getstage, 0); run(sendreq); } func(getflow) { load(address, 3); load(function, 3); load(register, 0); load(length, 2); load(getstage, 1); run(sendreq); } func(gettemp) { load(address, 3); load(function, 3); load(register, 2); load(length, 2); load(getstage, 2); run(sendreq); } page(mypage, stPage) { posn(0,0); draw(p1, 480, 46, stDraw1); posn(170,20); text(snt, "Serial No :", stText1r); posn(178,20); text(snv, "178324", stText1l); posn(206,110); text(flt, "Flow :", stText2r); posn(308,110); text(flv, "27", stText2r); posn(320,113); text(flu, "mln/min", stText1l); posn(206,185); text(tet, "Temp :", stText2r); posn(308,185); text(tev, "15.5", stText2r); posn(320,188); text(teu, "\\b0C", stText1l); run(getdata); } func(timeout) { // serial number request timeout if(getstage=0?[text(snv,"-");;run(getflow);exit(timeout);]); // flow request timeout if(getstage=1?[text(flv,"-");;run(gettemp);exit(timeout);]); // temp request timeout if(getstage=2?[text(tev,"-");;run(getserial);exit(timeout);]); } func(rxfunc) { // process incoming data 1 byte at a time load(rxbuffer.rxptr, RS4); if(rxptr=0?[if(rxbuffer.rxptr<>address?[exit(rxfunc);]:[calc(rxptr, rxptr, 1, "+");exit(rxfunc);]);]); if(rxptr=1?[if(rxbuffer.rxptr<>3?[load(rxptr,0);exit(rxfunc);]:[calc(rxptr, rxptr, 1, "+");exit(rxfunc);]);]); if(rxptr=2?[calc(rxlen, rxbuffer.rxptr, 5, "+");calc(rxptr, rxptr, 1, "+");exit(rxfunc);]); if(rxptr>2?[calc(rxptr, rxptr, 1, "+");if(rxptr=rxlen?update);]); } func(update) { load(rxptr, 0); load(TIMER1, 0); // check for valid checksum calc(temp, rxlen, 2, "-"); calc(csum, rxbuffer, temp, "", "CRC16"); calc(csumH, csum, 256, "/"); calc(csumL, csum, 256, "%"); calc(temp, rxlen, 1, "-"); load(csumHp, rxbuffer.temp); calc(temp, rxlen, 2, "-"); load(csumLp, rxbuffer.temp); // request same data again if checksum incorrect if(csumL<>csumLp?[run(sendreq);exit(update);]); if(csumH<>csumHp?[run(sendreq);exit(update);]); // otherwise update page entities and request next data if(getstage=0?[run(updateserial);exit(update);]); if(getstage=1?[run(updateflow);exit(update);]); if(getstage=2?[run(updatetemp);exit(update);]); } func(updateserial) { // serial number is stored as u32 value load(tval, rxbuffer.3); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.4, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.5, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.6, "+"); text(snv, tval); run(getflow); } func(updateflow) { // flow rate is stored as f32 value so requires conversion to decimal floating point load(tval, rxbuffer.3); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.4, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.5, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.6, "+"); calc(fval, tval, "CFLT"); text(flv, fval); run(gettemp); } func(updatetemp) { // temperature is stored as f32 value so requires conversion to decimal floating point load(tval, rxbuffer.3); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.4, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.5, "+"); calc(tval, tval, 256, "*"); calc(tval, tval, rxbuffer.6, "+"); calc(fval, tval, "CFLT"); text(tev, fval); // update page show(mypage); // start timer to get next set of data from flow controller load(TIMER0, pollinterval, 1); } show(mypage);