合泰单片机串口通讯C语言
C语言实现串口通信
![C语言实现串口通信](https://img.taocdn.com/s3/m/b4eec85f5e0e7cd184254b35eefdc8d377ee1416.png)
C语言实现串口通信在使用系统调用函数进行串口通信之前,需要打开串口设备并设置相关参数。
打开串口设备可以使用open(函数,设置串口参数可以使用termios结构体和tcsetattr(函数。
以下是一个简单的串口通信接收数据的示例代码:```c#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>int mainint fd; // 串口设备文件描述符char buff[255]; // 存储接收到的数据int len; // 接收到的数据长度//打开串口设备fd = open("/dev/ttyS0", O_RDONLY);if (fd < 0)perror("Failed to open serial port");return -1;}//设置串口参数struct termios options;tcgetattr(fd, &options);cfsetspeed(&options, B1200); // 设置波特率为1200 tcsetattr(fd, TCSANOW, &options);//接收数据while (1)len = read(fd, buff, sizeof(buff)); // 从串口读取数据if (len > 0)buff[len] = '\0'; // 将接收到的数据转为字符串printf("Received data: %s\n", buff);}}//关闭串口设备close(fd);return 0;```这段代码首先通过open(函数打开串口设备文件"/dev/ttyS0",然后使用tcgetattr(函数获取当前设置的串口参数,接着使用cfsetspeed(函数设置波特率为1200,最后使用tcsetattr(函数将设置好的串口参数写回。
合泰C语言用户手册
![合泰C语言用户手册](https://img.taocdn.com/s3/m/063462b10722192e4536f6bf.png)
函数 ....................................................................................................27
数组 ....................................................................................................28
注释 ......................................................................................................2
标识符..........................................................................................................3
位数据类型 ........................................................................................25
内嵌式汇编语言 ................................................................................26
条件运算符 ..........................................................................................9
逗号运算符 ..........................................................................................9
c语言串口通信范例完整版
![c语言串口通信范例完整版](https://img.taocdn.com/s3/m/6ed94c4fed630b1c59eeb590.png)
c语言串口通信范例标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]一个c语言的串口通信程序范例标签:分类:最近接触一个项目,用HL-C1C激光位移传感器+易控组态软件完成生产线高度跳变检测,好久没有接触c c#,一些资料,找来做个记录,也许大家用的着#include <>#include <>#include <>#include <>#define COM232 0x2f8#define COMINT 0x0b#define MaxBufLen 500#define Port8259 0x20#define EofInt 0x20static int comportaddr;static char intvectnum;static unsigned char maskb;static unsigned char Buffer[MaxBufLen];static int CharsInBuf,CircIn,CircOut;static void (interrupt far *OldAsyncInt)();static void interrupt far AsyncInt(void);void Init_COM(int ComPortAddr, unsigned char IntVectNum, int Baud, unsigned char Data, unsigned char Stop, unsigned char Parity) {unsigned char High,Low;int f;comportaddr=ComPortAddr;intvectnum=IntVectNum;CharsInBuf=0;CircIn=0;CircOut=0;f=(Baud/100);f=1152/f; High=f/256;Low=f-High*256;outp(ComPortAddr+3,0x80);outp(ComPortAddr,Low);outp(ComPortAddr+1,High);Data=(Data-5)|((Stop-1)*4);if(Parity==2) Data=Data|0x18;else if(Parity==1) Data=Data|0x8; outp(ComPortAddr+3,Data);outp(ComPortAddr+4,0x0a);outp(ComPortAddr+1,0x01);disable();OldAsyncInt=getvect( IntVectNum ); setvect( IntVectNum, AsyncInt ); enable();maskb=inp(Port8259+1);if(IntVectNum==0x0c)outp(Port8259+1,maskb&0xef); else outp(Port8259+1,maskb&0xf7);}static void interrupt far AsyncInt(void){disable();if(CharsInBuf<MaxBufLen)Buffer[CircIn]=inp(comportaddr);if(CircIn<MaxBufLen-1) CircIn++;else CircIn=0;if(CircIn==CircOut) CircOut++;else CharsInBuf++;enable();outp(Port8259,EofInt);}void Restore(void){setvect(intvectnum,OldAsyncInt);outp(Port8259+1,maskb);}int GetCharInBuf(unsigned char *Char) {int Flag;Flag=-1;if(CharsInBuf>0){(*Char)=Buffer[CircOut];if(CircOut<MaxBufLen-1)CircOut++;else CircOut=0;CharsInBuf--;Flag=0;}return Flag;}int SendChar(unsigned char Char){if((inp(comportaddr+5)&0x20)==0) return -1; outp(comportaddr,Char);return 0;}main(){int i,c;unsigned char InChar;Init_COM(COM232,COMINT,1200,8,1,0);while(1){if(kbhit()){if((InChar=getch())==27)break; else while(SendChar(InChar)); }if(GetCharInBuf(&InChar)==0)printf("%c",InChar);}Restore();}接收程序:#include <>#include <>#include <>#include <>#include <>#include <>#define RXD 0 .);void putb(unsigned char ch).){unsigned char ch;ch=inportb(portaddr+RXD);putb(ch);incount++; n");exit(1);}else{printf("The used port is :COM%d\n",ComNum); };Getportaddr(port); .#else#define __CPPARGS#endif#define SER_RBF 0#define SER_THR 0#define SER_IER 1#define SER_IIR 2#define SER_LCR 3#define SER_MCR 4#define SER_LSR 5#define SER_MSR 6#define SER_DLL 0#define SER_DLH 1#define SER_BAUD_1200 96 #define SER_BAUD_2400 48 #define SER_BAUD_9600 12 #define SER_BAUD_19200 6 #define SER_GP02 8#define COM_1 0x3F8#define COM_2 0x2F8 /*/ base port address of port 1*/#define COM_3 0x3E8#define COM_4 0x2E8#define SER_STOP_1 0 /*/ 1 stop bit per character*/#define SER_STOP_2 4 /*/ 2 stop bits per character*/#define SER_BITS_5 0 /*/ send 5 bit characters*/#define SER_BITS_6 1 /*/ send 6 bit characters*/#define SER_BITS_7 2 /*/ send 7 bit characters*/#define SER_BITS_8 3 /*/ send 8 bit characters*/#define SER_PARITY_NONE 0 /*/ no parity*/#define SER_PARITY_ODD 8 /*/ odd parity*/#define SER_PARITY_EVEN 24 /*/ even parity*/#define SER_DIV_LATCH_ON 128 /*/ used to turn reg 0,1 into divisor latch*/ #define PIC_IMR 0x21 /*/ pic's interrupt mask reg.*/#define PIC_ICR 0x20 /*/ pic's interupt control reg.*/#define INT_SER_PORT_0 0x0C /*/ port 0 interrupt com 1 & 3*/#define INT_SER_PORT_1 0x0B /*/ port 0 interrupt com 2 & 4*/#define SERIAL_BUFF_SIZE 128 /*/ current size of circulating receivebuffer*/void interrupt far (*Old_Isr)(__CPPARGS); /*/ holds old com port interrupt handler*/char ser_buffer[SERIAL_BUFF_SIZE]; /*/ the receive buffer*/int ser_end = -1,ser_start=-1; /*/ indexes into receive buffer*/int ser_ch, char_ready=0; /*/ current character and ready flag*/int old_int_mask; /*/ the old interrupt mask on the PIC*/int open_port; /*/ the currently open port*/int serial_lock = 0; /*/ serial ISR semaphore so the buffer*//*/ isn't altered will it is being written*//*/ to by the ISR*//*-------------写串口-----------------*/void interrupt far Serial_Isr(__CPPARGS){serial_lock = 1;ser_ch = inp(open_port + SER_RBF);if (++ser_end > SERIAL_BUFF_SIZE-1)ser_end = 0;ser_buffer[ser_end] = ser_ch;++char_ready;outp(PIC_ICR,0x20);serial_lock = 0;}int Ready_Serial(){return(char_ready);}/*--------------读串口--------------*/ int Serial_Read(){int ch;while(serial_lock){}if (ser_end != ser_start){if (++ser_start > SERIAL_BUFF_SIZE-1)ser_start = 0;ch = ser_buffer[ser_start];printf("%x",ch);if (char_ready > 0)--char_ready;return(ch);}elsereturn(0);}/*--------------写串口-----------------*/ Serial_Write(char ch){while(!(inp(open_port + SER_LSR) & 0x20)){}asm clioutp(open_port + SER_THR, ch);asm sti}/*-----------初始化串口---------------*/Open_Serial(int port_base, int baud, int configuration) {open_port = port_base;disable();outp(port_base + SER_LCR, SER_DIV_LATCH_ON);outp(port_base + SER_DLL, baud);outp(port_base + SER_DLH, 0);outp(port_base + SER_LCR, configuration);outp(port_base + SER_MCR, SER_GP02);outp(port_base + SER_IER, 1);if (port_base == COM_1 || port_base==COM_3){Old_Isr = _dos_getvect(INT_SER_PORT_0);_dos_setvect(INT_SER_PORT_0, Serial_Isr);printf("\nOpening Communications Channel Com Port #1/3...\n");}else{Old_Isr = _dos_getvect(INT_SER_PORT_1);_dos_setvect(INT_SER_PORT_1, Serial_Isr);printf("\nOpening Communications Channel Com Port #2/4...\n");}old_int_mask = inp(PIC_IMR);outp(PIC_IMR, (port_base==COM_1) (old_int_mask & 0xEF) : (old_int_mask & 0xF7 ));enable();/*-------------关闭串口--------------*/Close_Serial(int port_base){outp(port_base + SER_MCR, 0);outp(port_base + SER_IER, 0);outp(PIC_IMR, old_int_mask );if (port_base == COM_1){_dos_setvect(INT_SER_PORT_0, Old_Isr);printf("\nClosing Communications Channel Com Port #1.\n"); }else{_dos_setvect(INT_SER_PORT_1, Old_Isr);printf("\nClosing Communications Channel Com Port #2.\n");}/*-------------发送应用----------------*/ void main(int argc,char *argv[]){char ch,press;int done=0;FILE *fp;argc=2;//argv[1]="c:\\";if(argc<2){printf("\nUsage:display !!!");// exit(1);}if((fp=fopen(argv[1],"r+b"))==NULL)printf("cannot open the file\n");// exit(0);}fseek(fp, 0, SEEK_SET);Open_Serial(COM_1,SER_BAUD_9600,SER_PARITY_EVEN| SER_BITS_8 | SER_STOP_1); printf("com:1;bps:9600;parity:even;bits:8;stop bit:1");printf("press any key to begin sending");getch();//Serial_Write(''); //该语句可用于发送单个字符while(!done&&ch != EOF) //发送文件开始{ch = fgetc(fp);//if(ch==EOF) Serial_Write(27);Serial_Write(ch);delay(30);if (kbhit()){press=getch();if (press==27){Serial_Write(27);done=1;}}}Close_Serial(COM_1);fclose(fp);}下面介绍最重要的MFC:CWnd:窗口,它是大多数“看得见的东西”的父类(Windows里几乎所有看得见的东西都是一个窗口,大窗口里有许多小窗口),比如视图CView、框架窗口CFrameWnd、工具条CToolBar、对话框CDialog、按钮CButton,etc;一个例外是菜单(CMenu)不是从窗口派生的。
串口通信之用C语言编写串口程序
![串口通信之用C语言编写串口程序](https://img.taocdn.com/s3/m/1e003954a36925c52cc58bd63186bceb19e8edb8.png)
串口通信之用C语言编写串口程序在当今,流行的编程软件种类繁多,它们编程方便、易于维护,但是在与硬件直接打交道和编制系统软件时却束手无策,于是C语言就有了用武之地。
C语言作为汇编语言与高级语言之间的一种过渡语言,兼有汇编语言的高效和高级语言的方便。
在通讯中,为了保证行运安全可靠,标准的串行口必须具有许多握手信号和状态信息。
这是因为通讯的各个计算机CPU速度不一样(这会导致“错帧”)以及发送机发送数据速度比接收机接收速度快(这会导致“过冲”)。
为解决这个问题,我们采用一个简单的握手信号,即发送机每次仅发送半个字节(低4位)的数据,而另外半个字节(高4位)则用来传送信息。
我们可以对信息位(高4位)进行如下简单的编码:0H:发送的是新的半个字节数据1H:重新发送上次传送错误的数据2H:文件名结束3H:文件结束这样,每当发送机发送一个字节以后,就等待接受机发回送信号,这回送信号就是发送机发送过来的那个字节。
发送机接收到回送信号后,把它与刚发送的字节相比较,如果相同,就发送新的半个字节,否则就重新发送。
新数据与旧数据通过信息位来区分。
下面就是用C 语言编写控制串行口的程序。
#include "dos.h"#include "stdlib.h"#include "stdio.h"#define PORT 0void SendFile(char *fname); /* 发送文件*/void Send(int s); /*发送一个字节*/void SendFileName(char *fname); /*发送文件名*/void ReceiveFile(); /*接收文件*/void GetFileName(char *f); /*接收文件名*/void InitPort(int port,unsigned char para); /*初始化端口*/ void SendPort(int port,char c); /*端口发送*/int ReadPort(int port); /*读端口字节*/int CheckState(int port); /*检查端口状态*/int Receive(int port,int *G); /*接收一个字节*/main(int argc,char *argv[]){if(argc<2){printf("Please input R(receive) or S(sent) parametre:"); exit(1);}InitPort(PORT,231);if(*argv[1]==''''S'''') /*检查选择的有效性*/SendFile(argv[2]);else if(*argv[1]==''''R'''')ReceiveFile();else{printf("Error parament.Please input again.");exit(1);}}void SendFile(char *fname){FILE *fp;int ch,s;if((fp=fopen(fname,"rb"))==NULL){printf("Can''''t open the file.\n");exit(1);}SendFileName(fname);do{ch=(int)getc(fp);if(ferror(fp)){printf("Error reading file.\n");break;}s=ch%16; /*取文件中一个字节的低4位*/ Send(s);s=ch/16; /*取文件中一个字节的高4位*/ Send(s);}while(!feof(fp));s=46; /*发送文件结束信息*/Send(s);Send(s);fclose(fp);}void Send(s)int s;{int G;SendPort(PORT,s);G=ReadPort(PORT); /*等待握手信号*/ if(s!=G)s=s+16;do{SendPort(PORT,s);G=ReadPort(PORT);/*等待握手信号*/}while(s!=G);}void SendFileName(fname)char *fname;{int s,ch;printf("Now transmit the file.Please wait..."); while(*fname){ch=(int)fname++;s=ch%16; /*取文件名中一个字节的低4位*/ Send(s);s=ch/16;Send(s); /*取文件名中一个字节的低4位*/}s=32; /*发送文件名结束标志*/Send(s);Send(s);}void ReceiveFile(){FILE *fp;char ch;int G1,G2,G3;char fname[15];GetFileName(fname);printf("Receiving file %s.\n",fname); remove(fname);if((fp=fopen(fname,"wb"))==NULL){printf("Can''''t open output file.\n");exit(1);}/*循环为检测每次接受的数据是否为新数据,如果不是,*//*则用此次接收的数据覆盖上次接收的数据*/G1=ReadPort(PORT);G2=Receive(PORT,&G1);do{G3=Receive(PORT,&G2);ch=(char)(G1%16+G2*16);/*恢复分开的数据,组合高4位和低4位*/putc(ch,fp);if(ferror(fp)){printf("\nError writing file.");exit(1);}G2=Receive(PORT,&G3);G1=G3;}while(G1/16!=48);printf("\nTransmit finished.");fclose(fp);}int Receive(port,G)int port,*G;{int GM;SendPort(port,*G);GM=ReadPort(port);if(GM/16==0)return GM;else if(GM/16==1){do{*G=GM;SendPort(port,GM);GM=ReadPort(port);}while(GM/16==1);}return GM;}void GetFileName(char *f){int G1,G2,G3;char ch;G1=ReadPort(PORT);G2=ReadPort(PORT);do{G3=Receive(PORT,&G3);ch=(char)(G1%16+G2/16);*f=ch;*f++;G2=Receive(PORT,&G3);G1=G3;}while(G1/16!=32);printf("File name transmit finished.\n"); }void InitPort(port,para)int port;unsigned char para;{union REGS reg;reg.x.dx=port;reg.h.ah=0;reg.h.al=para;int86(0x14,?,?);}void SendPort(port,c)int port;char c;{union REGS reg;reg.x.dx=port;reg.h.al=c;reg.h.ah=1;int86(0x14,?,?);if(reg.h.ah&128){printf("\nSend mistakes!");exit(1);}}int ReadPort(port)int port;{union REGS reg;while(!(CheckState(port)&256)){if(kbhit()){/*如端口长期无数据可人为终止等待*/ printf("Press any key to exit.");getch();exit(1);}}reg.x.dx=port;reg.h.ah=2;int86(0x14,?,?);if(reg.h.ah&128){printf("\nRead mistake!");exit(1);}return reg.h.al;}int CheckState(port)int port;{union REGS reg;reg.x.dx=port;reg.h.ah=3;int86(0x14,?,?);return reg.x.ax;}在当今,流行的编程软件种类繁多,它们编程方便、易于维护,但是在与硬件直接打交道和编制系统软件时却束手无策,于是C语言就有了用武之地。
Holtek C语言学习教程
![Holtek C语言学习教程](https://img.taocdn.com/s3/m/9eb0c87227284b73f24250ac.png)
第一课时1、Holtek公司编译器HT-IDE3000使用说明(1)双击打开HT-IDE3000,进入编译器的界面,见下图:(2)单击“工程”——>选择“新建”,弹出下图窗口;——Project Name:新建项目文件的名称,不建议使用中文名称;——Project Location:项目文件存放的位置,勾选“Create directory for project”后,会自动建立一个文件夹,项目文件都存放在此文件夹内;——Project MCU:单片机的型号;——Choose Language Tool:选择编程语言,这里选择“V2”版本的C语言。
(3)点击下一步,选择“.C”;(4)点击下一步,再点击下一步,点击OK,然后弹出“配置选项”,配置选择只要是对单片机一些功能和特性进行设置,例如工作电压,工作频率,看门狗等;(5)配置选项设置完后,点击OK,再点击确定,那么新的工程就建立完毕了。
2、C语言程序设计(1)主函数每个程序只有一个主函数,程序是从主函数开始执行。
格式:void main(){}例子:#include "HT66F40.h"void main()//程序从这里开始跑{_nop();//语句1_nop();//语句2_nop();//语句3}功能说明:程序执行的顺序,语句1—>语句2—>语句3。
(2)子函数一个程序包含各种功能,如果每种功能都做成一个子函数,那么整个程序的架构实现了模块化。
例如,LCD的开启,显示及关闭这三个功能可以分别做成三个独立的子函数。
使用子函数的步骤:①编写子函数的功能void TurnOn_LCD()//LCD开启子函数,TurnOn_LCD是函数的名称{_nop();//这里先用空指令代表子函数的功能_nop();//这里先用空指令代表子函数的功能}②声明子函数,告诉单片机有这个子函数存在void TurnOn_LCD();技巧:直接把步骤①的第一行复制过来,然后在后面加上分号;③调用子函数TurnOn_LCD();例子:#include "HT66F40.h"void TurnOn_LCD();//声明子函数,告诉单片机有这个子函数存在void TurnOff_LCD();//声明子函数,告诉单片机有这个子函数存在void display_LCD();//声明子函数,告诉单片机有这个子函数存在void main(){_nop();//空指令_nop();//空指令_nop();//空指令while(1) //while循环结构,当小括号里内容为真,执行{//while大括号里的内容TurnOn_LCD(); //调用LCD开启子函数display_LCD();//调用LCD显示子函数TurnOff_LCD();//调用LCD关闭子函数}}void TurnOn_LCD()//编写子函数的功能,LCD开启子函数,TurnOn_LCD是{ //函数的名称_nop();//这里先用空指令代表子函数的功能_nop();//这里先用空指令代表子函数的功能}void TurnOff_LCD()//编写子函数的功能,LCD关闭子函数,TurnOff_LCD是{//函数的名称_nop();//这里先用空指令代表子函数的功能_nop();//这里先用空指令代表子函数的功能}void display_LCD()//编写子函数的功能,LCD显示子函数,display_LCD是{//函数的名称_nop();//这里先用空指令代表子函数的功能_nop();//这里先用空指令代表子函数的功能}(3)中断子函数使用中断子函数的步骤:①相关寄存器进行初始化(请查阅相关型号IC的PDF)②声明中断子函数地址格式:#pragma vector 中断子函数名称@中断入口地址例如:#pragma vector isr_tm0@0x14③编写中断子函数的功能例如:void isr_tm0(){}例子:#include "HT66F40.h"#pragma vector isr_tm0 @0x14//声明中断子函数的入口地址void mcu_init();//声明单片机初始化子函数void main(){mcu_init();while(1)//while循环结构,当小括号里内容为真,执行while{//大括号里的内容_nop();_nop();}}void isr_tm0()//编写中断子函数的功能{_t0af=0;//清除中断标志位_nop();//这里先用空指令代表中断子函数的功能}void mcu_init()//编写单片机初始化子函数{//定时器相关寄存器初始化_tm0c0=0b00000000;//定时器计数时钟fsys/4=1Mhz,fsys=4Mhz为系统//频率_tm0c1=0b11000001;//选择定时计数工作模式,//清0计数器的条件:与比较器A匹配,即//计数值与tm0al,tm0ah的值相等时,计数器清0)_tm0al=0xe8;//0x03e8=1000_tm0ah=0x03;_t0on=1;//启动定时器//定时器中断相关寄存器初始化_emi=1;//总中断控制位,0-关闭1-开启_mf0e=1;//多功能中断0控制位,0-关闭1-开启_t0ae=1;//TM0比较器A匹配中断控制位,0-关闭1-开启}(4)函数的返回值及参数的介绍①无返回值,无参数函数:前面介绍的函数均为无返回值无参数函数。
单片机应用技术基础(C语言)-串行口通信技术
![单片机应用技术基础(C语言)-串行口通信技术](https://img.taocdn.com/s3/m/e41b36d34bfe04a1b0717fd5360cba1aa8118cc6.png)
串行口通信技术
6.2.4 波特率设计计算与常用波特率 1. 波特率设计计算 在串行通信中,收发双方对发送或接收的数据速率要有
一定的约定,通过软件对串行口编程可约定4种工作方式。 其中方式0和方式2的波特率是固定的,而方式1和方式3的波 特率是可调的,由定时器的溢出率决定。
串行口通信技术
对方式1和方式3的波特率设计,实际上是通过对定时器 设计实现的。定时器1的溢出率取决于单片机定时器1的工作 方式和计数初值X。定时器1作波特率发生器使用时,通常 选用具有自动重装载初值功能的方式2,那么定时器每过 “256-X”个机器周期,定时器1就会产生一次溢出。定时 器1的溢出率可用以下公式表示:
1. 任务目的 了解51系列单片机串行口的结构,掌握其使用方法。 2. 任务要求 发送方向接收方发送数据,接收方接收数据并将数据在 P1口通过8个LED发光二极管以二进制形式显示出来。
串行口通信技术
3. 硬件电路 U1为发送方,U2为接收方,将双方的RXD(P3.0)和 TXD(P3.1)交叉互连即可,如图6.1所示。图中最小系统没有 画,本任务仅涉及单向通信,所以只需将发送方的TXD连 接至接收方的RXD即可。
串行口通信技术
异步通信中有两个重要指标:数据帧格式和波特率。 1) 数据帧格式 数据帧通常由起始位、数据位、奇偶校验位和停止位四 部分组成。 (1) 起始位:表示传送一个数据的开始,用低电平表示, 占一位。 (2) 数据位:要传送的数据的具体内容,典型的数据位 数是7位或8位,一般为7位(ASCII 码),数据从低位开始传 送。
串行口通信技术
2. 电源控制寄存器PCON PCON主要是为CHMOS型单片机的电源控制而设置的 专用寄存器,其字节地址为87H, 没有位寻址功能。 PCON的格式为
[电子工程] 单片机C语言之串口通信协议(代码分享)
![[电子工程] 单片机C语言之串口通信协议(代码分享)](https://img.taocdn.com/s3/m/fb50bd45d4d8d15abf234e12.png)
现实生活中,我们总是要与人打交道,互通有无。
单片机也一样,需要跟各种设备交互。
例如汽车的显示仪表需要知道汽车的转速及电动机的运行参数,那么显示仪表就需要从汽车的底层控制器取得数据。
而这个数据的获得过程就是一个通信过程。
类似的例子还有控制器通常是单片机或者PLC与变频器的通信。
通信的双方需要遵守一套既定的规则也称为协议,这就好比我们人之间的对话,需要在双方都遵守一套语言语法规则才有可能达成对话。
通信协议又分为硬件层协议和软件层协议。
硬件层协议主要规范了物理上的连线,传输电平信号及传输的秩序等硬件性质的内容。
常用的硬件协议有串口,IIC,SPI,RS485,CAN和USB。
软件层协议则更侧重上层应用的规范,比如modbus协议。
好了,那这里我们就着重介绍51单片机的串口通信协议,以下简称串口。
串口的6个特征如下。
(1)、物理上的连线至少3根,分别是Tx数据发送线,Rx数据接收线,GND共用地线。
(2)、0与1的约定。
RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。
TTL电平,约定5V的电压信号为1,0V电压信号为0 。
CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。
其中,CMOS电平一般用于ARM芯片中。
(3)、发送秩序。
低位先发。
(4)、波特率。
收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。
也可理解为每秒可以传输的位数。
常用的波特率有300bit/s, 600bit/s, 2400bit/s, 4800bit/s, 9600bit/s。
(5)、通信的起始信号。
发送方在没有发送数据时,应该将Tx置1 。
当需发送时,先将Tx置0,并且保持1位的时间。
接受方不断地侦测Rx,如果发现Rx常时间变高后,突然被拉低(置为0),则视为发送方将要发送数据,迅速启动自己的定时器,从而保证了收发双方定时器同步定时。
(6)、停止信号。
发送方发送完最后一个有效位时,必须再将Tx保持1位的时间,即为停止位。
合泰单片机C语言教程讲解
![合泰单片机C语言教程讲解](https://img.taocdn.com/s3/m/0f8293a1168884868662d671.png)
Holtek 微控制器應用範例–使用Holtek C 語言目錄第一章內容簡介第二章選定Holtek C 語言的使用環境2.1 進入HT-IDE3000 建立新的專案時, 選定Holtek C 編譯器2.2 已開啟專案後, 選用Holtek C 編譯器第三章微控制器C 語言程式的速成3.1 定義主函式main()3.2定義副函式(sub-function)3.3定義全域變數(global variable)3.4定義中斷服務函式(Interrupt Service Routine : ISR)3.5 其他第四章 C 語言程式4.1 C 程式架構4.2 開始用C 語言設計一個程式4.2.1 定義主函式main4.2.2 將標頭檔引入(include a header file)4.2.3 定義文字符號及變數4.2.4 設定微控制器及裝置的初始狀態4.2.5 設計子函式4.2.6 設計中斷服務函式4.3變數(variable) 及資料型態(data type)4.3.1 變數名4.3.2 資料型態4.3.3 變數的有效範圍(scope)4.3.4 變數的資料型態(data type)整數型(integer)浮點型(floating point)4.3.5 bit 資料型態4.3.6儲存類別(storage class) 與修飾詞(qualifier)儲存類別(storage class)修飾詞(qualifier)4.3.7絕對變數(absolute variable)4.3.8常數(constant)4.3.9指標(pointer) 與陣列(array)指標的運算子& 與*陣列(array)4.3.10結構(struct) 與等位(union)結構的運算子-> 與.4.4運算子(Operators)運算前的型態轉換4.5程式流程控制(program flow control)4.5.1if-else 敘述4.5.2switch 敘述4.5.3for 敘述4.5.4while 敘述4.5.5do-while 敘述4.5.6goto 敘述4.5.7break 與continue 敘述4.6函式(Functions)4.6.1參數(arguments)4.6.2返回值(return values)4.7中斷服務函式(Interrupt Service Routines)4.8在C 語言程式中嵌入組合語言(in-line assembly code)從組合語言的程式去存取 C 語言的物件(變數)4.9前置處理指令(Preprocessor)4.9.1 定義文字符號(#define)4.9.2引入檔案(#include)4.9.3內嵌組合語言(inline assembly)4.9.4 條件式編譯(#if/#endif)4.9.5 編譯器的特殊選項pragma4.10Holtek C 編譯器的內建函式(built-in functions)第五章基本 C 語言程式5.1 語法觀念5.2 迴圈的應用(loop)5.3 撰寫MCU 應用程式的注意事項5.4 可供微控制器應用程式使用的範本5.5 設計微控制器應用程式的小技巧第六章程式範例–初級6.1LED 跑馬燈6.2LED 霹靂燈6.3 單顆七段顯示器6.4 5*5 點矩陣LED 顯示6.5 HT48 微控制器控制HT1621 LCD 的顯示6.6 HT48 微控制器控制LCD 模組的顯示6.7 具LCD 驅動功能的微控制器之顯示應用程式– HT46R636.8 顯示器的通用函式– HT44780 LCM6.9 鍵盤掃描程式第七章程式範例–中斷函式7.1 用時鐘控制LED 的亮與滅7.2 類比/數位轉換(ADC) 的應用第八章HT46R52A 應用於鎳氫電池充電器(HA0084T)第九章程式範例– HT46R74D-1 胎壓計(HA0105T)第一章內容簡介盛群半導體公司(Holtek)開發一系列的八位元微控制器(micro-controller, MCU). 當開發微控制器的應用程式時, 除了可使用盛群提供的組合語言(assembly language),也可使用標準的C 語言編譯器(C compiler).由於八位元微控制器的記憶體空間, 不論是程式記憶體(program memory space)或是資料記憶體(ram memory space), 皆是有限制的, 通常會使用組合語言開發應用程式. 但是越來越多的微控制器支援更多的記憶體以及更多的功能, 使得程式也相對的擴大. 如果仍然使用組合語言開發程式, 不但費時費力, 未來在維護及擴增功能的工作上也相當困難.因此, 使用高階程式語言, 例如C 語言, 來開發應用程式就是一種可行的趨勢.C 語言是高階程式語言中的一種, 它具有高度的的可讀性及可移植性(portability),除了能夠快速地完成應用程式的開發與偵錯, 也很容易移植到其他的微控制器上. 當程式需要縮減或擴充功能時, 也很容易的完成, 因此很適合於微控制器的程式開發.本書主要是以Holtek C 語言為主, 說明如何使用Holtek C 語言撰寫盛群微控制器的應用程式, 包括 C 的程式架構, C 語言的一般用法, 特殊用法及應用範例書中將說明在開發微控制器的應用程式時需要注意的地方及如何撰寫會比較恰當, 並配以實例解釋.讀者可以參考修改或直接採用到自己的程式中, 再用發展工具HT-ICE, HT-IDE3000 驗證之.第二章介紹選用Holtek C 編譯器的步驟, 指引HT-IDE3000 呼叫Holtek C 編譯器去編譯C 語言的原始程式.第三章提供一種快速撰寫 C 程式的方法, 對ANSI C 語言熟悉的用者, 可於閱讀本章之後即開始撰寫微控制器的 C 語言程式第四章介紹C 語言, 未曾使用過 C 語言的讀者應仔細閱讀本章以了解 C 語言的用法第五章介紹使用 C 語言寫程式的基本觀念, 注意事項及建議的寫作方法第六章到第九章則是應用範例, 針對盛群各系列的微控制器, 以 C 語言撰寫的應用程式. 包含有功能說明, 應用電路及程式說明.文件編號版別 1.20日期2008/5/26 第5 頁共189 頁第二章選定Holtek C 編譯器的使用環境2.1 進入HT-IDE3000, 建立新的專案時, 選定Holtek C 編譯器進入HT-IDE3000 開發環境後, 依照下列方法建立一個新的專案(project)→ 移動滑鼠游標到Project 選單, 按左鍵→ 移動滑鼠游標到New 命令, 按左鍵→ 出現如下的視窗, 在Language Tool 之處勾選Enhanced Holtek C compiler/Assembler文件編號版別 1.20日期2008/5/26 第6 頁共189 頁2.2 已開啟專案後, 如何選用Holtek C 編譯器若專案(project) 已開啟之後, 可以點選(click) Option 選單下的Project Setting 命令,在Language Tool 中點選Enhanced Holtek C Compiler/Assembler 以設定使用Holtek C 的Enhance 版編譯器Enhance 版的C compiler 包括ehcc32srsc.exe , ehcc32mrsc.exe 與ehcc32mrmc.exe 三個執行檔此版本必須在HT-IDE3000 V7.0 或以上的系統才能執行第三章微控制器 C 語言程式的速成本章介紹如何快速撰寫微控制器的 C 語言應用程式. 已熟悉ANSI C 標準語言的用法或有撰寫的經驗者, 在閱讀此章後即可開始設計撰寫微控制器的 C 應用程式, 以下各節是基本的C 程式成員, 某些是必須要有的, 如3.1, 其他的則視微控制器的功能及應用來決定是否需要3.1 定義主函式main()#include “ht46r63.h”void main(void){int Flag ;……TurnOn_LCD() ;Flag = LCD_display(cstr) ;TurnOff_LCD() ;……}主函式的返回資料型態(return type)必須是void, 而且不能有參數檔案ht46r63.h 定義與微控制器有關的常數, 例如暫存器的位址定義, 將之引入(include) 可增加程式的可讀性.3.2定義副函式(sub-function)視程式的大小及功能決定是否需要定義副函式. 基本上, 主函式應將應用程式的架構做成模組化, 不需要將所有的程式皆放在主函式中. 為了能很快的完成及了解應用程式, 主函式中只需要包含(呼叫) 定義各功能的副函式即可, 無論在設計或維護程式時皆能很快的進入與完成.例如, 關於LCD 的開啟, 顯示及關閉等功能就可分別定義為單獨的副函式, 如下例. 任何其他的函式或其他的應用專案都可去呼叫這些副函式. 若設計成通用型的, 也可藉由程式館管理器(Library Manager) 將之建入程式館檔案, 以供其他應用專案使用.void TurnOn_LCD(void){}int LCD_display(char *cstr){}void TurnOff_LCD(void){}3.3定義全域變數(global variable)程式在運行中會需要一些變數做為資料存放的地方, 由於微控制器資料記憶體大小的限制及C 編譯器的設計, 最好將常需使用的變數定義為全域型的變數, 在編譯程式的大小與執行上皆較佳. 例如定義常數型指標變數cstr 指到字串“Hello!”, 則可如下const char *cstr = “Hello!” ;3.4定義中斷服務函式(Interrupt Service Routine : ISR) 若微控制器的周邊裝置具有中斷功能,程式也需要此中斷機能以完成工作時, 則必須定義此周邊裝置的中斷服務函式(Interrupt Service Routine, ISR), 如下的格式#pragma vector ISR_tmr0 @ 0x0cvoid ISR_tmr0(void){tick++ ;}中斷服務函式必須遵守下列規定→ 返回的資料型態必須是void→ 不能有參數(必須為void)→ 必須使用前置處理指令#pragma vector 設定中斷向量值(interrupt vector), 在函式名稱(本例子是ISR_tmr0) 之後加上@ 及中斷向量值(本例是0x0c). 也可使用先前定義好的常數, 例如#define VECTOR_TMR0 0x0c#pragma vector ISR_tmr0 @ VECTOR_TMR0void ISR_tmr0(void){}3.5 其他上述的主函式, 副函式及中斷服務函式不需要定義在同一個原始程式檔案內. 為縮短編譯的時間, 最好是分別定義在不同的檔案中, 並使用有意義的檔名, 方便日後找尋所要的函式.第四章 C 程式語言基本上, Holtek C 是仿ANSI (美國國家標準局) 標準的 C 語言, 為配合盛群八位元微控制器的架構, 將提供一些特殊的語法去存取或控制微控制器的資源. 另外, 本章會從八位元微控制器的角度, 說明如何使用 C 語言設計及撰寫微控制器的應用程式4.1 C 程式架構C 語言的程式是由敘述(statements) 所組成, 每個敘述的最後必須有分號‘;’ 做為結束符號.敘述分為四類:→ 宣告(declaration), 宣告變數及資料型態, 資料結構.例如char flag, tick_cnt ; // 宣告變數flag 與tick_cnt 為char 型態→ 定義(definition), 定義變數數值及位址例如int total = 10 ; // 定義變數total, 設定值為10→ 描述式(expression), 執行數學及邏輯運算, 控制程式的流程例如count = ( input > 10) ? 10 : input ;→ 函式呼叫(function), 執行函式的功能例如putchar(ch) ; // 寫出一個字元到輸出口每個敘述可以附加註解做說明. C 編譯器不會對註解做編譯, 下列為兩種可被接受的註解→ 介於符號/* 與符號*/ 之間的數據及文字, 包括換行字‘\n’如果/* 與*/ 不在同一行, 則其間所有的行皆會被視為註解例如/* this is a comment 1 */→ 從符號// 開始到本行的結束皆被視為註解例如// 這是註解的新寫法在 C 語言中, 程式執行區(program block)是以函式的格式定義, 因此, 所有要執行的敘述皆需定義(包含)於某個函式(function) 中, 例如描述式.4.2 開始用C 語言設計一個程式依照下列步驟¸使用 C 語言實作一個簡單的應用程式4.2.1 定義主函式main範例void main(void){}在 C 語言中, 主函式main 是程式執行的起點, 有如組合語言程式中的startORG 00jmp startstart :void 是資料型態, main 與void 皆是保留字, 必須用此字, 小寫字母4.2.2 將標頭檔引入(include a header file)範例#include “ht46r63.h”// 引入標頭檔ht46r63.hvoid main(void){}標頭檔ht46r63.h 中定義許多與微控制器有關的變數及文字符號(symbol). 接下來寫程式時可以使用這些變數與文字符號(symbol), 好處是寫程式或維護程式時會很容易了解程式的功能, 增加程式的易讀性. 例如unsigned char _pa @0x12 ;定義_pa 是一個unsigned char 型態的變數, 它的位址在RAM 的0x12 (就是A埠, port A). 所以程式中如下的敘述_pa = 0 ;則與組合語言的CLR PA ; (PA=[12H]) 有相同的功能4.2.3 定義文字符號及變數在程式中使用文字符號能夠更容易的讀懂程式及修改, 例如定義文字符號_pa0 如下#define _pa0 _12_0表示_pa0 是RAM 位址12H 的位元0 (bit 0), 就是 A 埠的位元0. 下列敘述_pa0 = 1 ;表示將 A 埠的位元0 設為1, 與組合語言程式的SET [12H].0 有相同的功能前置處理指令#define 是定義一個文字符號代表數值, 或是文字串, 或是巨集指令.C 編譯器的前置處理器(preprocessor) 在編譯前, 會先替換這些定義的文字符號.前置處理指令#undef 是將先前定義過的文字符號取消, 變成無效. 詳細的說明請參閱第 4.9 節微控制器中其他暫存器的變數或文字符號, 皆定義於對應之微控制器的標頭檔案內, 在設計程式時可參考之. 可以定義一些程式需要, 但是在標頭檔案中沒有定義的變數或文字符號, 方便程式的開發及維護, 例如#include #define “ht48R50A-1.h”scl _pa3 // SCL (時鐘線) 接到MCU 的A 埠的第3 位元#define scl_c _13_3 // A 埠之控制暫存器的第3 位元(bit 型變數)#define sda _pa1 // SDA (資料線) 接到MCU 的A 埠的第1 位元#define sda_c _13_1 // A 埠之控制暫存器的第1 位元void main(void){}定義四個文字符號scl, scl_c, sda, sda_c 分別代表不同的輸出/輸入埠定義變數會佔用RAM/ROM 的空間, 如果又指定位址, 則此變數佔用此位址, 否則Linker 在做連結時才會分派位址給變數. 其效果有如組合語言的_pa DB ?定義文字符號的效果則與組合語言的EQU 相同, 例如#define scl _pa3 與scl EQU _pa3有相同的效果4.2.4 設定微控制器及裝置的初始狀態根據程式的功能, 設定微控制器中各裝置的初始值, 例如周邊設備的初始狀態, 暫存器的型態等.scl_c = 0 ; // 設定SCL (= PAC) 的狀態為輸出sda_c = 0 ; // 設定SDA (=PA) 的狀態為輸出4.2.5 設計子函式獨立之功能可分別用子函式完成, 在程式的偵錯, 維護及重複使用上皆有好處. 在設計時需要注意函式的參數,返回值等. 通常會將主函式main() 放在程式檔的最後, 各個子函式定義在前面或其他的程式檔案內. 下列範例只是部份, 詳細的說明可參閱4.6 節.#include “ht48r50a-1.h”// 引入標頭檔#define scl _pa3 // SCL (時鐘線) 接到MCU 的A 埠的第 3 位元#define scl_c _13_3 // A 埠(位址0x13)之控制暫存器的第3 位元(bit 型變數) #define sda _pa1 // SDA (資料線) 接到MCU 的A 埠的第1 位元#define sda_c _13_1 // A 埠(位址0x13)之控制暫存器的第1 位元// 函式: StartCondition() 子函式// 功能: 開始一個命令// 輸入: 無// 輸出: 無void StartCondition(void){sda = 1 ; // SDA 輸出highscl = 1 ; // SCL 拉highsda = 0 ; // SDA 輸出lowscl = 0 ; // 完成Start of command}// 函式: StopCondition()// 功能: 結束先前的命令// 輸入: 無// 輸出: 無void StopCondition(void){}// 函式: main()// 功能: 主函式// 輸入: 無// 輸出: 無void main (void){unsigned char Rdata, type ;// 暫存器的初始設定scl_c = sda_c = 0 ; // 將A 埠的位元1, 3 設為輸出型態(SCL, SDA 為輸出)StartCondition() ; // 呼叫子函式……}4.2.6 設計中斷服務函式針對有硬體中斷的微控制器, 需要設計中斷服務函式以處理中斷事件定義周邊裝置的中斷服務函式(Interrupt Service Routine, ISR) 如下格式#pragma vector ISR_tmr0 @ 0x0cvoid ISR_tmr0(void){tick++ ;}中斷服務函式必須遵守下列規定→ 返回的資料型態必須是void→ 不能有參數→ 必須設定中斷向量值(interrupt vector), 在函式名稱(本例子是ISR_tmr0之後加上@ 及中斷向量值(本例是0x0c). 也可使用先前定義好的常數, 例如#define VECTOR_TMR0 0x0c#pragma vector ISR_tmr0 @ VECTOR_TMR0void ISR_tmr0(void){}4.3變數(variable) 及資料型態(data type)程式執行過程中, 可能會需要暫存一些資料, 例如旗標, 執行次數, 延遲秒數等, 因此就必須定義變數以儲存這些資料. 由於變數要佔用程式記憶體(PROM) 或資料記憶體(RAM), 因此在使用變數之前, 定義變數的資料型態, 以便讓編譯器正確的編譯程式及配置記憶體空間.除了資料型態之外, 還可加入儲存類別(storage class) 及修飾詞(qualifier), 對變數做更詳細的安置.4.3.1 變數名變數名的規則→ 第一個字元必須是英文字母或底線符號(underscore), 之後可緊接著字母或數字→ 變數名的前32 個字元有效→ 變數名內不可有+, - , *, / , ……等符號字元→ 英文字母的大小寫是有區別的(case-sensitive), 例如count 與Count 是不同的變數名範例, number, total_tick, _tick 是合法的變數名, 而2num, $dot, line\n 是非法的變數名4.3.2 資料型態* float, double 皆使用IEEE754 32 位元的格式4.3.3 變數的有效範圍(scope)根據變數定義的所在¸決定此變數的有效範圍. 可分為→ 區域變數(local variable)定義在程式區塊內(program block, 例如函式)的變數皆是區域變數. 只有當此程式區塊被執行時, 區域變數才會有效, 而在執行完畢並離開此程式區塊後, 這些區域變數將無效. 程式區塊是指包含在左右大括號‘{‘ 及‘}’ 之間的敘述行定義在函式中的static 變數則是全域變數, 參考 4.3.2 說明→ 全域變數(global variable)定義在所有函式之外的變數為全域變數. 當程式在執行時, 此變數皆有效, 任何函式都可以存取或修改這個變數範例#include “ht48r50a-1.h”unsigned char flag ; // 全域變數void main(void){ char type ; // 區域變數, 只有在此函式被執行時才有效static status = 0 ; // static 變數, 只在第一次執行時設為0……}4.3.4 變數的資料型態(data type)當宣告變數時,必須指定它的資料型態, 以告知編譯器此變數所需記憶體的大小. 資料型態分為整數型(integer type)及浮點數型(floating point type). 整數型又可區分為有正負號(signed) 及無正負號(unsigned).整數型(integer)→ char佔用一個位元組(byte) 的記憶體空間. 如加上signed 則表示有正負號, 其大小範圍是–128 到127. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0到255. 如果沒有signed 或unsigned, 則被視為signed. 可用此型態定義字元,如‘A’, ‘d’, ‘$’, ‘3’等→ short佔用兩個位元組(2 bytes) 的記憶體空間, 如加上signed 則表示有正負號, 其大小範圍是–32768 到32767. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0 到65535. 如果沒有signed 或unsigned, 則被視為signed.Holtek C 採用little-endian 格式, 就是變數的低位元組(least significant byte) 存放在記憶體的低位址. 例如變數count = 0x1234 是存放於記憶體40H 的位址, 則低位元組的數值0x34 存放於位址40H, 高位元數值0x12 存放於位址41H.→ int與short 型態相同→ long佔用四個位元組(4 bytes) 的記憶體空間, 如加上signed 則表示有正負號, 其大小範圍是–2147483648 到2147483647. 若加上unsigned, 則表示沒有正負號, 其大小範圍是0 到4294967295. 如果沒有signed 或unsigned, 則被視為signed在little-endian 格式中, 32位元的變數, 則是先存低字元(least significant word) 的低位元組(least significant byte)到記憶體的低位址, 再存放低字元的高位元組(high byte), 再存放高字元(high word)的低位元組, 最後才是高字元的高位元組浮點型(floating point)Holtek C 支援IEEE 754 32 位元的格式. 包括float 及double 兩個資料型態, 浮點數值是以下表的格式儲存在記憶體與浮點數值的關係式為number = (-1)sign x 2(exponent – 127) x 1.mantissa例如, 浮點數為 2.77000e+37 在儲存到記憶體時換成7DA6B69B 共佔32 位元4.3.5 bit 資料型態類似整數型, 但是只有0 或 1 兩個值, 所以只會取整數的最低位值(LSB:least significant bit) 需要注意下列用法→ bit 型態不可與auto 一起使用, bit 型態的變數不可當函式的參數, 不可用於指標(pointer) 的數據型態, 不可設定靜態初始值(static)→ bit 型態可以設為函式的返回型態, 它是存於累加器(accumulator) 的相對位置→ 程式開始執行時, 不會設定bit 型變數的初始值, 因此程式必須自行設定初始值→ 以下是合法的使用方式static bit init_flag ; // 定義於函式內則被視為區域變數bit toggle_flag ;→ 範例int data = 0x54 ;bit flag ;flag = data ;則flag = 0 (取data 的LSB)如果微控制器具有一個以上的RAM bank, 例如HT46R63, 在定義bit 型態的變數時需要使用前置處理指令#pragma rambank0 指定在RAM bank 0, 如下#pragma rambank0bit flag ;#pragma norambank4.3.6儲存類別(storage class) 與修飾詞(qualifier)變數於宣告或定義時必須指定其資料型態, 但是儲存類別及修飾詞是可選擇的, 可根據應用時的需要去設定或不使用.儲存類別(storage class)儲存類別與區域變數(local variable)及全域變數(global variable)有關.→ 儲存類別autoauto 是給區域變數使用的, 沒有指定儲存類別的區域變數皆是auto寫與不寫auto 都是相同效力. 區域變數是存放在RAM bank 0 的空間→ 儲存類別registerregister 與auto 類似, 是給區域變數用的, 當變數的存取很頻繁時, 可將之設為register, C 編譯器會使用暫存器而非資料記憶體空間來存放此變數, 如此可增加存取的速度及減少編碼. 目前並未實做此功能.→ 儲存類別staticstatic 的變數會一直有效到整個程式結束後才失效. 它的初始值只會在程式開始執行時被設定一次. 雖然static 的變數在程式結束前皆有效, 但是定義在函式內的static 變數仍然是區域變數, 必須要在它所定義的函式中才可以讀寫→ 儲存類別externextern 通知C 編譯器此變數是定義在其他的程式檔內, 需要經由連結器(Linker)連結定義此變數的檔案後, 才知道變數的所在.以目前在微控制器的應用程式上, 比較需要使用extern, 其他三種不具特別的優勢可用定義全域變數(global variabl)的方式即可達到相同效果. 建議不要使用.修飾詞(qualifier)→ 修飾詞constC 編譯器會將const 的變數放置於程式記憶體(PROM). 在定義const 變數時, 必須要設定其值, 而程式在執行中不能修改此變數的值→ 修飾詞constant這個修飾詞是Holtek C 編譯器特別提供的. 它會將constant 的變數放置於程式記憶體(PROM) 的最後一頁(last page). 定義constant 變數時,必須要設定其值, 而程式在執行中不能修改此變數的值. 使用此修飾詞要注意下列三點●只能使用在int 或unsigned int 的資料型態●設定值必須配合微控制器程式記憶體的寬度, 例如, 若使用在 HT48R50A-1 時,因為此微控制器的寬度為 15 個位元, 最高位元是無效的, 所以 0x9A 會被 C編譯器改成 0x1A. 最高位元, 位元 15 被清除為 0● 所有設定此修飾詞的變數或陣列, 總共佔用的字位元組 (word) 不可超過 256 個指定詞(specifier)→ 指定詞typedeftypedef 是針對資料型態做新名稱的宣告, 不是宣告資料型態的新變數, 而是宣告一個新的名字. 例如將UCHAR (新名字) 宣告為unsigned char 的資料型態, 可使用typedef unsigned char UCHAR ; // UCHAR 為unsigned char 的新名字UCHAR count ; // 變數count 的資料型態為unsigned char// 等同於unsigned char count ;使用typedef 宣告資料型態的新名字可以讓程式的可讀性更高, 更易了解. 例如,typedef unsigned int WORD ; // 使用WORD 代表unsigned int, 16 bitstypedef unsigned long DWORD ; // DWORD 代表32 bit 的double word4.3.7絕對變數(absolute variable)可以將全域變數或static 變數指定一個固定的記憶體的位址, 例如unsigned char PortA @ 0x12 ;在變數名的後面再加上‘@’及位址C 編譯器在編譯時會將程式中出現絕對變數的程式改為此位址, 但並未在記憶體中保留位置給此變數, 所以從連結器(Linker) 產出的對映檔(map file)中找不到此變數 C 編譯器會將之翻成組合語言的EQU 指令,如下_PortA EQU 12h此種用法主要是對微控制器內的暫存器做定義, 方便閱讀程式4.3.8常數(constant)整數型常數(integral constant) 可使用基底(radix)格式表示之.若常數的最後一字為l 或L, 則表示它使用signed long 或unsigned long 的型態. 字尾是u 或U, 則表示常數為unsigned 型態.浮點型(floating point)常數的型態是double, 若它的字尾是 f 或F, 則是float.字元常數(character constant)必須以單引號‘ ‘ 框住, 例如‘a’字串常數(string constant) 必須以雙引號“ “ 框起, 例如“Hello!”. 字串常數的定義會影響它所儲存的記憶體位址, 如下char *cp = “one” ; // C 編譯器會發出錯誤const char *sptr = “Hello” ; // “Hello” 儲存在程式記憶體(PROM) 常數型的變數或陣列(array)必須要設定其值, 否則C 編譯器會發出錯誤訊息,如上例4.3.9指標(pointer) 與陣列(array)指標本身是一個變數, 它的內容是另一個變數存放的位址, 類似組合語言的間接定址.在使用上, 指標必須要指到一個已定義(存放於記憶體) 的變數, 否則在程式執行時會發生錯誤. 指標的宣告格式資料型態*指標名[, *指標名,….] ; 資料型態是這個指標所指的變數的資料型態, 例如char. 指標名類似變數名, 可以在一行中, 宣告指向相同資料型態的不同指標名, 例如char *tptr, *array_ptr ;int *line_ptr ;以上只是宣告指標變數, 必須要將這些指標指向已定義的變數才能使用指標的運算子& 與*運算子& 如果緊鄰在變數的前面, 例如&line, 則是代表取得此變數的記憶體位址例如,int line ; // 定義變數int *line_ptr ; // 宣告指標line = 12 ;line_ptr = &line ;若變數line 被安置於RAM 的位址64, 則指標line_ptr 等於64運算子* 緊鄰指標變數之前是表示取得這個指標指到的變數的內容, 承上例, int total ; // 定義變數total = *line_ptr ; // 取得指標line_ptr 所指到的變數line 的內容則變數total 等於12指標的大小會根據微控制器具有之記憶體空間大小而定, 如果微控制器具有一個以上的RAM bank, 則指標本身會使用兩個位元組來儲存被指到的變數的位址如果變數有const 或constant 修飾詞, 則是指向程式記憶體(PROM), 而且此變數的內容不能被修改. 如果所指向的變數不具有const 或constant, 則指標會指向資料記憶體(data memory, RAM) 內的變數.陣列(array)陣列是由相同資料型態的元素組成的, 例如char array_name[32] ;是由32 個char 型態的元素組成的, 這些元素的名字是以陣列名array_name 為準, 而以索引(index) 區分各個元素, 例如array_name[3] 是第 4 個元素. 陣列的索引是正整數, 從0 開始直到元素的總個數減一, 上例中, 最後一個元素是array_name[31]. 這種資料型態在建表格(table) 時非常有用陣列也可當做指標的一種, 只是使用時格式不同, 下列範例說明指標與陣列之間的使用方法char *nptr, *fptr ; // 宣告指標char ch, tbl ; // 定義變數char table[5] = { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ } ; // 定義陣列nptr = table ; // 指標nptr 指到陣列table 的第一個元素table[0]ch = *nptr ; // 將字元‘a’ 存入變數chtbl = table[0] ; // 將字元‘a’ 存入變數tbl , 所以變數ch 與變數tbl 的內容相同fptr = &table[4] ; // 指標fptr 指到陣列table 的第5 個元素, table[4]ch = *fptr ; // 將字元‘e’ (第5 個元素) 存入變數ch 內tbl = *(nptr+4) ; // nptr 指到陣列table 的第一個元素, 加4, 所以tbl = ‘e’4.3.10結構(struct) 與等位(union)結構是一個或多個成員的集合, 每個成員的資料型態可以不同, 並且使用結構的名字去讀寫這些成員. 結構的宣告是等同於定義一個新的資料型態, 當變數宣告為一個結構的型態時, 便可用結構的名字去讀寫各成員的內容.成員的資料型態不可以使用bit 型態, 但是可以用bit-field 方式宣告成員的型態, 例如struct str_name {unsigned flag : 1 ; // 此成員放於最低位元least significant bitunsigned no_used : 7 ;unsigned stack : 5 ; // 此成員置於最高位元high bits} usage ;每個bit field 會置放於16 位元的單位內, 不會橫跨兩個16位元的單位等位(union) 的格式與結構相同, 唯一不同的是記憶體空間的分配方式. 等位是安排共用的空間來存放不同資料型態的成員. 每個成員必須要宣告其資料型態, 而等位的大小則是所有成員中佔用最大位元組(bytes)的型態大小. 每個成員的開始位址皆相同, 就是等位的位址.union union_name {char num_byte ; // 佔用1 個位元組。
c语言怎么写串口通信编程
![c语言怎么写串口通信编程](https://img.taocdn.com/s3/m/ecd6c3d5dbef5ef7ba0d4a7302768e9951e76e3a.png)
c语言怎么写串口通信编程串口通信是一种广泛应用于嵌入式系统和电子设备之间的通信方式。
无论是嵌入式开发还是电子设备控制,串口通信都是常见的需求。
在C语言中,实现串口通信需要通过操作串口的硬件寄存器和使用相应的通信协议来实现数据的发送和接收。
本文将一步一步介绍如何使用C语言编写串口通信程序。
第一步:打开串口要开始串口通信,首先需要打开串口。
在C语言中,可以使用文件操作函数来打开串口设备。
通常,串口设备被命名为/dev/ttyS0,/dev/ttyS1等,具体名称取决于系统。
下面是一个打开串口设备的示例代码:cinclude <stdio.h>include <fcntl.h>include <termios.h>int open_serial_port(const char *port) {int fd = open(port, O_RDWR O_NOCTTYO_NDELAY);if (fd == -1) {perror("open_serial_port");return -1;}设置串口属性struct termios options;tcgetattr(fd, &options);cfmakeraw(&options);cfsetspeed(&options, B9600);tcsetattr(fd, TCSANOW, &options);return fd;}int main() {const char *port = "/dev/ttyS0";int fd = open_serial_port(port);if (fd == -1) {打开串口失败,处理错误return -1;}串口已打开,可以进行数据的读写操作return 0;}在上面的代码中,open_serial_port函数用于打开指定的串口设备并进行一些必要的设置。
单片机 c语言 通讯例程
![单片机 c语言 通讯例程](https://img.taocdn.com/s3/m/aba8c2fbf021dd36a32d7375a417866fb84ac081.png)
单片机c语言通讯例程摘要:I.单片机简介A.单片机的定义B.单片机的历史C.单片机的发展II.单片机C 语言A.C 语言的概述B.C 语言的优缺点C.C 语言在单片机中的应用III.单片机通讯例程A.通讯例程的定义B.通讯例程的作用C.通讯例程的实现IV.单片机C 语言通讯例程的应用A.在智能家居中的应用B.在工业自动化中的应用C.在医疗设备中的应用正文:单片机(Microcontroller Unit, MCU)是一种集成电路,它将CPU、存储器、外设接口等多种功能集成在一个芯片上,具有体积小、成本低、功耗低、功能强大等特点。
单片机的出现,极大地推动了计算机和电子领域的发展。
C 语言是一种通用的、过程式的计算机程序设计语言,被广泛应用于系统编程、嵌入式开发等领域。
C 语言具有语法简洁、可移植性强、运行效率高等优点,成为单片机开发的主要编程语言之一。
单片机通讯例程是单片机C 语言开发中的一个重要环节,主要是为了实现单片机与外部设备或计算机之间的数据通讯。
通讯例程可以通过串口通讯、I2C 通讯、SPI 通讯等方式实现。
通过通讯例程,单片机可以实现与各种外部设备的连接和控制,从而实现各种功能。
单片机C 语言通讯例程在各种领域都有广泛的应用。
在智能家居领域,可以用单片机实现智能门锁、智能照明、智能窗帘等设备的控制;在工业自动化领域,可以用单片机实现生产线的自动化控制、设备的监测与维护等;在医疗设备领域,可以用单片机实现医疗设备的控制和数据处理,如心电图机、血压计等。
总之,单片机C 语言通讯例程是单片机开发中的重要技术,它在各个领域都有着广泛的应用。
单片机C语言之串口通信协议
![单片机C语言之串口通信协议](https://img.taocdn.com/s3/m/6d7ecd00cfc789eb172dc8ac.png)
单片机C语言之串口通信协议
串口通信概述串口通信指串口按位(bit)发送和接收字节。
尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。
常用三种串口通信协议1、RS-232RS-232(ANSI/EIA-232标准)是IBM-PC及其兼容机上的串行连接标准。
可用于许多用途,比如连接鼠标、打印机或者Modem,同时也可以接工业仪器仪表。
用于驱动和连线的改进,实际应用中RS-232的传输长度或者速度常常超过标准的值。
RS-232只限于PC串口和设备间点对点的通信。
RS-232串口通信最远距离是50英尺。
从计算机连出的线的截面。
RS-232针脚的功能:
数据:
TXD(pin 3):串口数据输出(Transmit Data)
RXD(pin 2):串口数据输入(Receive Data)
握手:
RTS(pin 7):发送数据请求(Request to Send)
CTS(pin 8):清除发送(Clear to Send)
DSR(pin 6):数据发送就绪(Data Send Ready)
DCD(pin 1):数据载波检测(Data Carrier Detect)
DTR(pin 4):数据终端就绪(Data Terminal Ready)
地线:
GND(pin 5):地线
其它
RI(pin 9):铃声指示
2、RS-422RS-422(EIA RS-422-AStandard)是Apple的Macintosh计算机的串口连接标准。
合泰C语言用户手册
![合泰C语言用户手册](https://img.taocdn.com/s3/m/063462b10722192e4536f6bf.png)
字符型常量 ..........................................................................................6
字符串常量 ..........................................................................................6
指针与数组 ................................................................................................17
指针 ....................................................................................................17
保留字 ..................................................................................................3
数据类型 ......................................................................................................3
枚举常量 ..............................................................................................6
运算符..........................................................................................................7
c语言串口通信,协议解析写法
![c语言串口通信,协议解析写法](https://img.taocdn.com/s3/m/97a371edd0f34693daef5ef7ba0d4a7302766cc4.png)
c语言串口通信,协议解析写法在C语言中,串口通信通常使用串口库函数进行操作。
常用的串口库函数包括:`open()`: 打开串口设备文件`close()`: 关闭串口设备文件`read()`: 从串口读取数据`write()`: 向串口写入数据`ioctl()`: 对串口进行控制操作在进行串口通信时,需要定义通信协议,包括数据包的格式、数据包的发送和接收方式等。
下面是一个简单的示例,演示如何使用C语言进行串口通信并解析协议:```cinclude <>include <>include <>include <>include <>include <>define SERIAL_PORT "/dev/ttyUSB0" // 串口设备文件路径define BAUD_RATE B9600 // 波特率define PACKET_SIZE 1024 // 数据包大小int main() {int fd; // 串口设备文件描述符struct termios options; // 串口选项结构体char buffer[PACKET_SIZE]; // 数据包缓冲区int bytes_read; // 读取的字节数// 打开串口设备文件fd = open(SERIAL_PORT, O_RDWR O_NOCTTY O_NDELAY); if (fd == -1) {perror("open");exit(1);}// 配置串口选项tcgetattr(fd, &options);cfsetispeed(&options, BAUD_RATE);cfsetospeed(&options, BAUD_RATE);_cflag = (CLOCAL CREAD);_cflag &= ~PARENB; // 无奇偶校验位_cflag &= ~CSTOPB; // 一个停止位_cflag &= ~CSIZE; // 清空数据位掩码_cflag = CS8; // 设置数据位为8位_lflag &= ~(ICANON ECHO ECHOE ISIG); // 非规范模式,禁用回显和中断信号_iflag &= ~(IXON IXOFF IXANY); // 禁用软件流控制_oflag &= ~OPOST; // 不处理输出处理_cc[VMIN] = 1; // 读取至少一个字符_cc[VTIME] = 0; // 不超时tcsetattr(fd, TCSANOW, &options);// 从串口读取数据并解析协议while (1) {bytes_read = read(fd, buffer, PACKET_SIZE);if (bytes_read < 1) {perror("read");exit(1);}// 在这里添加协议解析代码,例如判断数据包的开头和结尾,提取有效数据等。
第11章-单片机 C 语言编程— —串口通信
![第11章-单片机 C 语言编程— —串口通信](https://img.taocdn.com/s3/m/afb87d771eb91a37f0115c10.png)
并在CP脉冲上升沿作用下决定Q0的状态。
11
11.2 了解74LS164/165芯片
74LS164真值输出情况如表11-1所示,时序逻辑如图11-4所示。
表11-1 74LS164真值表
输入 清零(/MR) L 时钟CP × A B × × 输出 Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7 L L L L L L L L
(c)全双工通讯方式
图11-1 三种通讯方式图
6
11.1 数据传输概念
通常以每秒传输多少位( bit/s )表示串行式数据传输的速率,又称为比特率( baud rate )。 51 单 片机 提供了 一个 全双工 的万 用异步 串行 端口 ( Universal Asynchronous
Receiver-Transmitter ,简称 UART ),这个串行端口有 4 种工作模式,分别为 Mode0 、
图11-2 74LS164引脚图
10
11.2 了解74LS164/165芯片
74LS164的内部逻辑如图11-3所示。
图11-3 74LS164内部逻辑图
当清除端(/MR)为低电平时,输出端Q0~Q7均为低电平。串行数据输入端 A、B可控数据。当A、B任意一个为低电平,则禁止新数据输入,在时钟端CP脉冲 上升沿作用下Q0为低电平。当A、B有一个为高电平,则另一个就允许输入数据,
图11-5 74LS165引脚图
13
11.2 了解74LS164/165芯片
74LS165真值输出情况如表11-2所示,时序逻辑如图11-6所示。
表11-2 74LS165真值表
输入 移位/装载 时钟禁止 时钟 串行数据输入 并行输入 A……H
a……h
合泰单片机串口通讯C语言
![合泰单片机串口通讯C语言](https://img.taocdn.com/s3/m/041c512378563c1ec5da50e2524de518964bd380.png)
合泰单片机串口通讯C语言/*和泰单片机串口通许,已调试通过,抗干扰超强,一些标志及定时器请自己定义*/ unsigned char count_uartout;//发送计数器unsigned cha datin_buf[4]; //接收寄存器4个unsigned cha datout_buf[9]; //发寄存器9个#define tongxun_in datin_buf[0] //接收送识辨码寄存器#define tongxun_out datout_buf[0] //发送识辨码寄存器#define send_max 8 //设发的数据个数DEFINE_ISR (Interrupt_uart, 0x2c) //串口中断地址{if(++count_uartin>3)count_uartin=0;if((_usr&0b11110000)==0) //判断是否出错{if(_rx8) //接收到首数据{tongxun_in=_txr_rxr;if(tongxun_in==0x5a) 首数据正常则{b_sendero=0; //清除错误标志count_uartin=0; //接收数据地址清零tongxun_time=0; //通许计时器清0,tongxun_time为1S计时器,到1S则b_tongxun=1;表示接收错误。
b_tongxun=0;}else b_sendero=1; //接收的数据出错}else //出错处理{if(!b_sendero)datin_buf[count_uartin]=_txr_rxr; //接收的数据正常else b_tongxun=_txr_rxr; //接收的数据出错,需读_txr_rxr清除_usr的错误标志}}elseb_tongxun=_txr_rxr;// //接收的数据出错,需读_txr_rxr清除_usr 的错误标志}//---------------------------------------------------void send_out( ) //P_cs p_clk p_din p_dout zhu {if(_txif){if(++count_uartout>send_max){count_uartout=0;_tx8=1;}else _tx8=0;_txr_rxr=datout_buf[count_uartout];}}pro_100ms(){ if(b_1000ms){b_100ms=0;if(++tongxun_time>15) b_tongxun=1;}}void main(){datout_buf=0x5a;_ucr1=0b11001001;_ucr2=0b11101100;_emi = 1; //开总中断_brg=6;//开串口中断_uarte=1;////开串口中断while(1){send_out( );}}。
单片机串口通信C程序及应用实例
![单片机串口通信C程序及应用实例](https://img.taocdn.com/s3/m/0e5381f77c1cfad6195fa7b9.png)
一、程序代码#include<STC12C5A.h>//该头文件可到网站下载#define uint unsigned int#define uchar unsigned charuchar indata[4];uchar outdata[4];uchar flag;static uchar temp1,temp2,temp3,temp;static uchar R_counter,T_counter;void system_initial(void);void initial_comm(void);void delay(uchar x);void uart_send(void);void read_Instatus(void);serial_contral(void);void main(){system_initial();initial_comm();while(1){if(flag==1){ES = 0;serial_contral();ES = 1;flag = 0;}elseread_Instatus();}}void uart_send(void){for(T_counter=0;T_counter<4;T_counter++){SBUF = outdata[T_counter];while(TI == 0);TI = 0;}T_counter = 0;}uart_receive(void) interrupt 4{if(RI){RI = 0;indata[R_counter] = SBUF;R_counter++;if(R_counter>=4){R_counter = 0;flag = 1;}}}void system_initial(void){P1M1 = 0x00;P1M0 = 0xff;P1 = 0xff; //初始化为全部关闭temp3 = 0x3f;//初始化temp3的值与六路输出的初始值保持一致temp = 0xf0;R_counter = 0;T_counter = 0;}void initial_comm(void){SCON = 0x50; //设定串行口工作方式:mode 1 ; 8-bit UART,enable ucvr TMOD = 0x21; //TIMER 1;mode 2 ;8-Bit ReloadPCON = 0x80; //波特率不加倍SMOD = 1TH1 = 0xfa; //baud: 9600;fosc = 11.0596IE = 0x90; // enable serial interruptTR1 = 1; // timer 1RI = 0;TI = 0;ES = 1;EA = 1;}void delay(uchar x){uchar i,j;for(i=0;i<x;i++)for(j=0;j<110;j++);}serial_contral(void){if(indata[3] == ((indata[0]^indata[1])^indata[2])){if(indata[1]== 0x01){P0 = 0xff;temp2 = P0; //读取四路输入// temp2 = temp2&0x0f;outdata[0] = 0xee;outdata[1] = 0x02;outdata[2] = temp2;outdata[3] = ((outdata[0]^outdata[1])^outdata[2]);uart_send();return;}if(indata[1]== 0x03){temp3 = indata[2];P1 = temp3; //控制六路输出return;}if(indata[1]==0x04){outdata[0] = 0xee;outdata[1] = 0x05;outdata[2] = temp3;outdata[3] = ((outdata[0]^outdata[1])^outdata[2]);uart_send();return;}}}void read_Instatus(void){P0 = 0xff;temp1 = P0; //读取四路输入if(temp1!=temp){delay(10);P0 = 0xff;temp1 = P0;if(temp1!=temp){temp = temp1;//P0 = 0xff;//temp = P0;//temp = temp&0x0f;outdata[0] = 0xee;outdata[1] = 0x06;outdata[2] = temp;outdata[3] = ((outdata[0]^outdata[1])^outdata[2]);uart_send();}}}//总结:原因在于串口中断接收一定要使用全局变量,并且这个变量R_counter和T_counter 要在主程序中初始化。
HOLTEK C语言学习教程
![HOLTEK C语言学习教程](https://img.taocdn.com/s3/m/d7828c2ea32d7375a41780be.png)
void main()
//程序从这里开始跑
{
_nop();
//语句 1
_nop();
//语句 2
_nop();
//语句 3
}
功能说明:程序执行的顺序,语句 1—>语句 2—>语句 3。
(2) 子函数
一个程序包含各种功能,如果每种功能都做成一个子函数,那么整个程序的架
构实现了模块化。
例如,LCD 的开启,显示及关闭这三个功能可以分别做成三个独立的子函数。
_nop(); _nop(); }
//编写子函数的功能,LCD 关闭子函数,TurnOff_LCD 是 //函数的名称 //这里先用空指令代表子函数的功能 //这里先用空指令代表子函数的功能
void display_LCD()
//编写子函数的功能,LCD 显示子函数,display_LCD 是
{
//函数的名称
4 变量命名规则
——第一个字符必须是英文字母或底线符号”_”,之后可紧接字母或数字。
——变量名不能超过 32 个字符。
——英文字母的大小写是有区别的。
例如:count,count2,_count,_count2
5 变量的有效范围
——定义在函数里面,变量有效范围在此函数范围内。
——定义在函数外面,变量有效范围是整个程序。
使用子函数的步骤:
1 编写子函数的功能
void TurnOn_LCD()
//LCD 开启子函数,TurnOn_LCD 是函数的名称
{
_nop();
//这里先用空指令代表子函数的功能
_nop();
//这里先用空指令代表子函数的功能
}
2 声明子函数,告诉单片机有这个子函数存在
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*和泰单片机串口通许,已调试通过,抗干扰超强,一些标志及定时器请自己定义*/ unsigned char count_uartout;//发送计数器
unsigned cha datin_buf[4]; //接收寄存器4个
unsigned cha datout_buf[9]; //发寄存器9个
#define tongxun_in datin_buf[0] //接收送识辨码寄存器
#define tongxun_out datout_buf[0] //发送识辨码寄存器
#define send_max 8 //设发的数据个数
DEFINE_ISR (Interrupt_uart, 0x2c) //串口中断地址
{
if(++count_uartin>3)
count_uartin=0;
if((_usr&0b11110000)==0) //判断是否出错
{
if(_rx8) //接收到首数据
{
tongxun_in=_txr_rxr;
if(tongxun_in==0x5a) 首数据正常则
{
b_sendero=0; //清除错误标志
count_uartin=0; //接收数据地址清零
tongxun_time=0; //通许计时器清0,tongxun_time为1S计时器,到1S则b_tongxun=1;表示接收错误。
b_tongxun=0;
}
else b_sendero=1; //接收的数据出错
}
else //出错处理
{
if(!b_sendero)
datin_buf[count_uartin]=_txr_rxr; //接收的数据正常
else b_tongxun=_txr_rxr; //接收的数据出错,需读_txr_rxr清除_usr的错误标志
}
}
else
b_tongxun=_txr_rxr;// //接收的数据出错,需读_txr_rxr清除_usr的错误标志
}
//---------------------------------------------------
void send_out( ) //P_cs p_clk p_din p_dout zhu {
if(_txif)
{
if(++count_uartout>send_max)
{
count_uartout=0;
_tx8=1;
}
else _tx8=0;
_txr_rxr=datout_buf[count_uartout];
}
}
pro_100ms()
{ if(b_1000ms)
{
b_100ms=0;
if(++tongxun_time>15) b_tongxun=1;
}
}
void main()
{
datout_buf=0x5a;
_ucr1=0b11001001;
_ucr2=0b11101100;
_emi = 1; //开总中断
_brg=6;//开串口中断
_uarte=1;////开串口中断
while(1)
{
send_out( );
}
}。