//本函数集来自“51单片机世界”,作者斑竹丁丁(聂小猛)。 //串口中断服务程序,仅需做简单调用即可完成串口输入输出的处理 //出入均设有缓冲区,大小可任意设置。 //可供使用的函数名: //char getbyte(void);从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。 //getline(char idata *line, unsigned char n); 获取一行数据回车结束,必须定义最大输入字符数 //putbyte(char c);放入一个字节到发送缓冲区 //putbytes(unsigned char *outplace,j);放一串数据到发送缓冲区,自定义长度 //putstring(unsigned char code *puts);发送一个定义在程序存储区的字符串到串口 //puthex(unsigned char c);发送一个字节的hex码,分成两个字节发。 //putchar(uchar c,uchar j);输出一个无符号字符数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //putint(uint ui,uchar j);输出一个无符号整型数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //delay(unsigned char d); 延时n x 100ns //putinbuf(uchar c);人工输入一个字符到输入缓冲区 //CR;发送一个回车换行 //************************************************************************* #include #defineucharunsigned char #defineuintunsigned int #defineOLEN32/* size of serial transmission buffer*/ idataunsigned charoutbuf[OLEN];/* storage for transmission buffer*/ unsigned char idata*outlast = outbuf; //最后由中断传输出去的字节位置 unsigned char idata*putlast = outbuf; //最后放入发送缓冲区的字节位置 #defineILEN12/* size of serial receiving buffer*/ idataunsigned charinbuf[ILEN]; unsigned char idata *inlast = inbuf; //最后由中断进入接收缓冲区的字节位置 unsigned char idata *getlast = inbuf; //最后取走的字节位置 bitoutbufsign0;//最后一个数据覵BUF发完标志发完=0 bitoutbufsign;//输出缓冲区非空标志有=1 bitinbufsign;//接收缓冲区非空标志有=1 bitinbufful;//输入缓冲区满标志满=1 #define CR putstring("\r\n")//CR=回车换行 //***************************** //延时n x 100ns void delay(unsigned char d)//在源程序开头定义是否用w77e58或22。1184M晶振 { unsigned char j; do { d--; //110592 & 89c52 #ifndef cpuw77e58 #ifndef xtal221184 j = 21; //k=38 cpu80320100us k=21 cpu 8052 #else j = 42; #endif #else #ifndef xtal221184 j = 38; #else j = 76; #endif #endif do { j--; } while (j != 0); } while (d != 0); } //***************************** //放入一个字节到发送缓冲区 putbyte(char c) { uchar i, j; ES = 0; /*暂停串行中断,以免数据比较时出错?*/ //if (outlast=putlast) while ((((outlast - putlast) == 2) && (outlast > putlast)) || ((outlast < putlast) && (OLEN - (putlast - outlast) == 2))) { ES = 1; c++; c--; ES = 0; // i=(0-TH1); // do{i--;j=39; do {j--;}while(j!=0); }while(i!=0);//i=39 } *putlast = c; //放字节进入缓冲区 putlast++;//发送缓冲区指针加一 if (putlast == outbuf + OLEN) { putlast = outbuf; //指针到了顶部换到底部 } outbufsign = 1; if (!outbufsign0) { outbufsign0 = 1; //缓冲区开始为空置为有,启动发送 TI = 1; } ES = 1; } //****************************** //放一串数据到发送缓冲区 putbytes(unsigned char *outplace, unsigned char j) { int i; for (i = 0; i { putbyte(*outplace); outplace++; } } //****************************** //输出一个无符号字符数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 //例如putchar(0x32,2),输出"4.8". //putchar(0x32,3),输出"0.48". //putchar(0x32,1),输出"48". putchar(uchar c, uchar j) { ucharidata free[4]; uchar data i; i = 0; free[i++] = (c / 100 + 0x30); if (j == 3) { free[i++] = '.'; } free[i++] = (c % 100) / 10 + 0x30; if (j == 2) { free[i++] = '.'; } if (j == 2 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } free[i++] = (c % 10) + 0x30; if (j == 1 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } if (j == 1 && free[i - 3] == 0x20 && free[i - 2] == 0x30) { free[i - 2] = 0x20; } putbytes(free, i); } //****************************** //输出一个无符号整型数的十进制表示,必须标示小数点的位置,自动删除前面无用的零 putint(uint ui, uchar j) { uchar idata free[6]; uchar data i; i = 0; free[i++] = (ui / 10000 + 0x30); if (j == 5) { free[i++] = '.'; } free[i++] = ((ui % 10000) / 1000 + 0x30); if (j == 4) { free[i++] = '.'; } if (j == 4 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } free[i++] = ((ui % 1000) / 100 + 0x30); if (j == 3) { free[i++] = '.'; } if (j == 3 && free[i - 4] == 0x30) { free[i - 4] = 0x20; } if (j == 3 && free[i - 4] == 0x20 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } free[i++] = ((ui % 100) / 10 + 0x30); if (j == 2) { free[i++] = '.'; } if (j == 2 && free[i - 5] == 0x30) { free[i - 5] = 0x20; } if (j == 2 && free[i - 5] == 0x20 && free[i - 4] == 0x30) { free[i - 4] = 0x20; } if (j == 2 && free[i - 5] == 0x20 && free[i - 4] == 0x20 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } free[i++] = (ui % 10 + 0x30); if (j == 1 && free[i - 5] == 0x30) { free[i - 5] = 0x20; } if (j == 1 && free[i - 5] == 0x20 && free[i - 4] == 0x30) { free[i - 4] = 0x20; } if (j == 1 && free[i - 5] == 0x20 && free[i - 4] == 0x20 && free[i - 3] == 0x30) { free[i - 3] = 0x20; } if (j == 1 && free[i - 5] == 0x20 && free[i - 4] == 0x20 && free[i - 3] == 0x20 && free[i - 2] == 0x30) { free[i - 2] = 0x20; } putbytes(free, i); } //*************************************** //发送一个定义在程序存储区的字符串到串口 putstring(unsigned char*puts) { for (; *puts != 0; puts++) { //遇到停止符0结束 putbyte(*puts); } } //************************************* //发送一个字节的hex码,分成两个字节发。 unsigned char code hex_[] = {"0123456789ABCDEF"}; puthex(unsigned char c) { int ch; ch = (c >> 4) & 0x0f; putbyte(hex_[ch]); ch = c & 0x0f; putbyte(hex_[ch]); } //************************************* //从接收缓冲区取一个byte,如不想等待则在调用前检测inbufsign是否为1。 uchar getbyte(void) { char idata c ; while (!inbufsign);//缓冲区空等待 ES = 0; c = *getlast; //取数据 getlast++;//最后取走的数据位置加一 inbufful = 0; //输入缓冲区的满标志清零 if (getlast == inbuf + ILEN) { getlast = inbuf; //地址到顶部回到底部 } if (getlast == inlast) { inbufsign = 0; //地址相等置接收缓冲区空空标志,再取数前要检该标志 } ES = 1; return (c);//取回数据 } //***************************************** //接收一行数据,必须定义放数据串的指针位置和大小del=0x7f,backspace=0x08,cr=0x0d,lf=0x0a void getline(uchar idata *line, unsigned char n) { unsigned char cnt = 0;//定义已接收的长度 char c; do { if ((c = getbyte()) == 0x0d) { c = 0x00; //读一个字节,如果是回车换成结束符 } if (c == 0x08 || c == 0x7f) { //BACKSPACE 和 DEL 的处理 if (cnt != 0) { //已经输入退掉一个字符 cnt--;//总数目减一 line--;//指针减一 putbyte(0x08); //屏幕回显的处理 putbyte(' '); putbyte(0x08); } } else { putbyte(*line = c); //其他字符取入,回显 line++;//指针加一 cnt++;//总数目加一 } } while (cnt < n - 1 && c != 0x00 && c != 0x1b); //数目到了,回车或ESC停止 *line = 0;//再加上停止符0 } //**************************** //人工输入一个字符到输入缓冲区 putinbuf(uchar c) { ES = 0; if (!inbufful) { *inlast = c; //放入数据 inlast++;//最后放入的位置加一 if (inlast == inbuf + ILEN) { inlast = inbuf; //地址到顶部回到底部 } if (inlast == getlast) { inbufful = 1; //接收缓冲区满置满标志 } inbufsign = 1; } ES = 1; } //***************************************** //串口中断处理 serial() interrupt 4 { if (TI) { TI = 0; if (outbufsign) //if (putlast==outlast) outbufsign=0; //else { SBUF = *outlast; //未发送完继续发送 outlast++;//最后传出去的字节位置加一 if (outlast == outbuf + OLEN) { outlast = outbuf; //地址到顶部回到底部 } if (putlast == outlast) { outbufsign = 0; //数据发送完置发送缓冲区空标志 } } else { outbufsign0 = 0; } } if (RI) { RI = 0; if (!inbufful) { *inlast = SBUF; //放入数据 inlast++;//最后放入的位置加一 inbufsign = 1; if (inlast == inbuf + ILEN) { inlast = inbuf; //地址到顶部回到底部 } if (inlast == getlast) { inbufful = 1; //接收缓冲区满置满标志 } } } } //***************************** //串口初始化0xfd=19200,0xfa=9600,0xf4=4800,0xe8=2400,0xd0=1200 serial_init() { SCON = 0x50; /* mode 1: 8-bit UART, enable receiver*/ TMOD |= 0x20;/* timer 1 mode 2: 8-Bit reload*/ PCON |= 0x80; TH1 = 0xfA;//fa,//baud*2/* reload value 19200 baud*/ TR1 = 1; /* timer 1 run*/ ES = 1; REN = 1; EA = 1; SM2 = 1; //SM2=1时收到的第9位为1才置位RI标志 TMOD |= 0x01; //th1 auto load 2X8,th0 1X16 TH0 = 31; TL0 = 0; //X 32 =1S TR0 = 1; //ET0=1; } //***************** //测试用主函数 void main(void) { char c; idataunsignedcharfree[16]; unsigned char idata *freep = free; serial_init(); putstring("jdioptuejls;j;klj"); delay(10); while (1) { putstring("com is ready! "); } c = getbyte(); putbyte(0x20); puthex(c); switch (c) { case 'r': putbytes(inbuf, ILEN); break; case 'g': getline(freep, 10); putbyte(0x20); putstring(freep); break; default: putbyte(c); // } } }