IO口模拟UART串口

     由于博主近期参与了合泰芯片的项目开发,所以此次就用合泰单片机来测试(具体型号为HT66F70A),IDE为HT-IDE3000(合泰官方)。

      首先需要了解两个概念:

      1.帧
IO口模拟UART串口_第1张图片
      是串行通讯的数据单元,其中各位的意义如下:
起始位:先发出一个逻辑”0”的信号, 表示传输数据的开始
数据位:紧接着起始位之后,数据位的个数可以是4、5、6、7、8等,(通常使用8位)构成一个字符,通常采用ASCII码, 从最低位开始传送,通过时钟定位
奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数( 奇校验),以此来校验资料传送的正确性。
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台 设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且 提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

2.波特率
是衡量数据传输速率的指标,表示每秒钟传送的符号数(symbol),单位为bit/s。博主使用的单片机为8Mhz的时钟,故定时器装载值=(时钟x定时时间)≈833(十进制)=341(十六进制),对相应寄存器赋值时_tm0al=0x41;(低八位赋值),_tm0ah =0x03;(高二位赋值);

     总结:使用的波特率为9600bps,传输1bit的时间约等于0.104ms。
               数据由1bit起始位+8bit数据位+1bit停止位共10bit的数据帧组成,起始位为低电平,停止位为高电平。
               IO口默认拉高,数据传输由低位到高位。
               当我们搞清楚原理之后,写代码什么的自然也就不在话下。实验中只需要配置好定时器0.104ms产生一次中断以保证每位之间的时间间隔即可。
/*********************合泰单片机IO口模拟UART串口通讯实验**********************/

UART源文件

#include "UART.h"
#include "HT66F70A.h"
#include "TM.h"
#include "String.h"

//全局变量区
volatile unsigned int flag = 0;
char buff[num];
char Buff[32] = "\0";
unsigned int count = 0;


void UART_INIT(void)
{
  TM0_INIT();      
}

void Waitflag(void)
{
	while (!flag);
	flag=0;//用flag模拟51单片机的计时器溢出标志TF0
}


void WByte(unsigned char input)
{

    unsigned char i=8;
    TXD=0;
    _t0on=1; //开始计时
    Waitflag();
    while(i--)
    {
        TXD=input & 0x01;         
        input >>= 1;
        Waitflag();
    }
    TXD=1;
    Waitflag();
    _t0on = 0;
        
}

void Send(char *buf)
{
	while(*buf != '\0')
	{
		WByte(*buf);
		buf++;
	}
}

void Send_num(unsigned int s,char *buf)
{
	while(s--)
	{
		WByte(*buf);
		buf++;
	}
}

	
void Send_Array(void)
{
	unsigned int i;
	for(i = 0;i < num;i++)
    WByte(buff[i]);		
}

unsigned char RByte(void)
{
    unsigned char receive;
    unsigned char i=8;
    while(RXD);
    _t0on=1;        //开始计时
    Waitflag();
    while(i--)
    {
        receive >>= 1;
        if(RXD)
        receive |= 0x80;
        Waitflag();
    }
    _t0on = 0;
    return receive;
}

void Receive(void)
{
    for(count = 0;count < num;count++)
    {		
	    
	    buff[count] = RByte();
	}
}

void Receive_num(unsigned int s,char *buf)
{
	while(s--)
	{
	*buf = RByte();
	buf++;
	}
}

void Receive_if(char *buf)
{
	char get;
	while(1)
	{
		get = RByte();
		if(get == '\n')
		break;
		else
		{
	    *buf = get;
	    buf++;
		}
	}
}

UART头文件

#ifndef _UART_H_
#define _UART_H_

//定义TXD RXD
#define TXD _pc2
#define RXD _pc3
//定义接收字符串长度
#define num 16

void UART_INIT(void);
void Waitflag();
void WByte(unsigned char input);
unsigned char RByte(void);
void Send(char *buf);//发送char型字符串
void Send_num(unsigned int s,char *buf);//发送s个字符
void Send_Array(void);//发送缓冲区
void Receive(void);//接收num个字符到缓冲区
void Receive_num(unsigned int s,char *buf);//接收s个字符
void Receive_if(char *buf);//以'\n'结尾的条件接收

#endif



定时器配置源文件
#include "HT66F70A.h"
#include "TM.h"

//专用于模拟串口的定时器
void TM0_INIT(void)
{
	//TXD RXD初始化
	_pcc2 = 0;
	_pcc3 = 1;
	_pcpu3 = 1;
	_pcpu2 = 1;
	
    _tm0c0=0x10;//计数器暂停运行控制,时钟选择,TM总开关TnPAU=1 暂停
    _tm0c1=0xc1;//工作模式,清零条件位                
    _tm0al=0x41;//设置波特率为9600
    _tm0ah=0x03; 
//    _tm0al=0x05;//设置波特率为2400
//    _tm0ah=0x0d; 

       
    _t0ae = 1;
    _t0af = 0;
    _t0on = 0;
    _emi = 1;
    _mf0e = 1;
    _mf0f = 0;
	}


定时器头文件

#ifndef _TM_H_
#define _TM_H_

void TM0_INIT(void);


#endif


中断服务头文件
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
#endif

#define ISR_TMR0//定义为TM0或TM2

void __attribute((interrupt(0x14))) ISR_tmr0_tmr2(void)//TM0和TM2公用中断入口
{
	//定义为ISR_TMR0时
	#ifdef ISR_TMR0
	extern volatile unsigned int flag;
	_emi = 0;
	_t0af = 0;
	flag = 1;
	_emi = 1;
	//定义为ISR_TMR2时
	#else
	_emi = 0;
	_t2af = 0;
	_emi = 1;
	#endif
	
	}

TEST主函数
#include "HT66F70A.h"
#include "Interrupt.h"
#include "TM.h"
#include "UART.h"
#include "String.h"


//全局变量区
extern char buff[num];
extern char Buff[32];
extern unsigned int count;

//函数声明区
void delay1s(void);


//主程序入口
void main()
{
    //TO DO
    _wdtc = 0xab;//看门狗失能
    unsigned char key;
    UART_INIT();
    Send("test");
    Send("单片机UART通讯测试");
    delay1s();
    Receive();
    Send_Array();
    Receive_if(Buff);
    //Send_num(8,Buff);
    Send(Buff);
    }
    while(1);		   
}

void delay1s(void)   //误差 -1us
{
    unsigned char a,b,c,n;
    for(c=205;c>0;c--)
        for(b=171;b>0;b--)
            for(a=8;a>0;a--);
    for(n=1;n>0;n--);
}
	

/****************************END******************************/
*此版为2018/4/3最新稳定更新版(copy可用版),还是老问题,接收时用Receive_if()做条件接收.


 
  

 
  

你可能感兴趣的:(编程)