2018-06-09 17:50:38 duidaifen3896 阅读数 3414
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3512 人正在学习 去看看 张先凤

  今天在用51单片机进行串口收发数据的时候遇到了这样一个问题,上位机给单片机的字符数据是什么类型的,单片机又是怎样存储的?

串口中断如下

/* UART中断服务函数 */
void InterruptUART() interrupt 4
{
	if (RI)  //接收到字节
	{
  	   RI = 0;  //手动清零接收中断标志位
  	   table1[j] = SBUF;  //接收到的数据保存到接收字节变量中
	   if(table1[0] == 0x0D)
  	       f = 1;
       else 
		   f =0;
       table1[j] = table1[j]&0x0f;
	   j++;
	   flag1 = 1;	
								
    }
    else  //字节发送完毕
    {
       TI = 0;  //手动清零发送中断标志位
       FS_Bit = 0;
    }
} 

问题1:

单片机将接收到的数据放到SBUF中存储,但这个SBUF只能存储8位数据(1个字节),那么就有了第一个问题:如何接收多位数据?

答:我是定义了一个table1[]数组,将每个接收到的8位数据放到数组里,然后指针自加1,在另一个中断里判断一共接收到了几个数据(j起自加和计数作用),然后延时1s后,将接收到的每个元素输出(1s足够接收到几个字节的数据了)。

问题2

那么table1[]里的数据是什么类型的呢?

答:它是一个二进制数据,是接收到字节的二进制ascii码,如果再用SBUF发送出去,也是发送的二进制数据,不过上位机接收的时候自动转换成字节了。

问题三

如何将接收到的二进制ascii码进行十进制运算呢?

答:其实二进制与十进制计算方法、过程、结果都一样。但是用字符类型传给单片机的数字的二进制与对应十进制的二进制是不一样的,比如说上位机字符格式发送过来一个数据2,单片机接收到的二进制ascii码0011 0010,而十进制的2对应的二进制是 0000 0010,所以不能直接对字符格式的数字进行运算,所以我用了

table1[j] = table1[j]&0x0f;
将高四位都清0,与十进制的2对应起来,然后就可以进行运算了。(但是上位机发送一个大写字母R与字符2是一样的,因为R的ascii码是 0000 0010)


2014-01-18 15:42:09 lidec 阅读数 2195
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3512 人正在学习 去看看 张先凤

/************************************************
功能:将整形转换为ascii码字符串
示例:dat = 12345   buffer[10]
      转换后
   buffer[0] = '1'
   buffer[1] = '2'
   ...
   buffer[4] = '5'
   buffer[5] = '\n'
**********************************************/
void DtoA(unsigned long dat, unsigned char* buffer)
{
  unsigned long tmp = dat;
  char length = 0;

  while(tmp != 0)//求出数字的实际长度
  {
    tmp = tmp/10;
    length++;
  }
  buffer[length] = '\0';//长度数为字符串截止位
  length--;

  while(length >= 0)//数字的低位放入数组的高位
  {
    tmp = dat%10;
    buffer[length--] = 0x30|tmp;

    dat = dat/10;
  }  
}

/****************************************************
功能:将ascii码字符串(非ascii也可)转换成对应数字

unsigned char code date[] = "1234567";     ->   返回 1234567
unsigned char code date_neg[] = "-1234567";      ->   返回 -1234567
****************************************************/
long mi(unsigned char dat, unsigned char mi)
{
  unsigned char i;
  long sum = 1;

  for(i=0; i<mi; i++)
  {
    sum = sum * dat;         
  }

  return sum;
}

long AtoD(unsigned char* buffer)
{
   long dat = 0, tmp = 0,k;
   unsigned char i;
   char j = 0;

   i = strlen(buffer);
   if(buffer[0] == '-')
   {
      j = 1;   
   }
   for(; j<i; j++)
   {
        tmp = buffer[j]&0x0f;//如果原数组中存放的是ascii码,直接将其转换为数字
   k = mi(10,i-j-1);
   tmp = k * tmp;
   dat += tmp;
    }

    if(buffer[0] == '-')
    {
      return -dat;
    }
 
    return dat;
}

void SendString(unsigned char* String)
{
  int i=0;
  while(String[i] != '\0')
  {
    SendData(String[i]);
    i++;
  }
}
void SendDig(long dat)
{
  char buffer[36];
  DtoA(dat, buffer);
  SendString(buffer);
}

2019-12-06 14:57:14 xiaoeleis 阅读数 37
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3512 人正在学习 去看看 张先凤

最近调试新唐的N76E003单片机的串口收发,官方及网上对单字节的收发的城西都有,很简单就完成了。

问题是比如:N76E003串口,接收连续数据不完整怎么解决,N76E003串口接收不定长的字符串怎么解决?

这里提供一个方案解决这个问题,采用中断方式完成串口接收,波特率 9600到115200 都没有问题:

参考官方案例为基础,这里不上多余的代码,请自行参考网络。

使用串口调试工具测试,需要注意的一点是,调试工具发送选择,请选中“加回车换行”


bit rcvFlg;

UINT16 recvCnt=0;

static UINT8 state=0;

#define UARTRCBUFSIZE  128
UINT8  UART_BUFFER[UARTRCBUFSIZE];

void main()

{

        InitialUART0_Timer3(115200);
        set_ES;           //enable UART interrupt 启用串口中断
        set_EA;           //enable global interrupt 启用全局中断

      while(1)                        
      { 

                if (rcvFlg)
                {
 
                        Uart0_SendString(UART_BUFFER);
 
                        set_ES;            //enable UART interrupt
                        SCON = 0x50;      //UART0 Mode1,REN=1,TI=1
                        rcvFlg= 0;
     
                    }
 
 
   }

}

void serial_IT(void) interrupt 4 
{
   

   if (RI) 
    {     
            UART_BUFFER[recvCnt++] = SBUF;                                  /* if reception occur */
            clr_RI;       /* clear reception flag for next reception */
            if((SBUF == '\0')||(SBUF == '\n'))  
            {
                 UART_BUFFER[recvCnt]='\0';
                 state = 1;
            }                
       
    }
        if(TI)
        {
            clr_TI;                             /* if emission occur */
        }

        if(state)
        {
            state = 0;
            UART_BUFFER[recvCnt]='\0';
            clr_ES;
            SCON=0x40; 
            rcvFlg =1;            
            recvCnt = 0;
        } 

}



 

2018-11-19 17:02:38 u014581350 阅读数 881
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3512 人正在学习 去看看 张先凤

1字符串输出到串口

////////////////////////////////////////////////////////
//单片机串口发送字符
////////////////////////////////////////////////////////
#include<reg51.h>		//51单片机头文件(单片机寄存器解释文件)
#include<stdio.h>		//输入输出函数头文件
void main(void)			//主函数
{	TI=1;				//串口发送标志
	while(1)			//主循环
	{
		printf("HELLO C!\r\n");//字符串输出到串口
	}
}

2LED闪烁

#include<reg51.h>
sbit LED=P3^7;				//定义特殊功能寄存器P3^7为LED
void main(void)
{
	unsigned int i;			//定义无符号16位数i
	while(1)
	{
	for(i=0;i<52000;i++)	//for循环,用于延时
		LED=~LED;			//LED取反操作
	}
}

3LED流水灯

#include<reg51.h>
void delay()//延时函数
{
	unsigned int i;
	for(i=0;i<52000;i++);	
}

void main()
{
	unsigned char i;			
	while(1)
	{
		for(i=0;i<8;i++)
		{
			P0=0x01<<i;//从右往左
			P0=0x80>>i;//从左往右
			delay();//调用延时函数
		}
	}
}

4定时器

#include<reg51.h>
sbit POUT=P1^0;
void main(void)
{
	TMOD=0x01;		//设置工作方式
	TH0=0xfc;		//装初值
	TL0=0x18;
	TR0=1;			//开定时器0
	while(1)
	{
		if(TF0==1)	//判断是否溢出
		{
			TF0=0;	//清除溢出标志
			TH0=0xfc;//重新装入初值
			TL0=0x18;
			POUT=!POUT;
		}
	}
}
  • 1.定时器/计数器原理框图
    在这里插入图片描述
  • 51单片机通常有两个16位寄存器/计数器(T0&T1)。
  • 每来一个脉冲,计数器+1。16位计数器技术范围为0000-FFFF。
  • 当输入脉冲通过单片机引脚输入,实现计数器功能。 当外部输入脉冲间隔确定时,计数器便可当定时器使用。
  • 加满后会产生溢出,并且清零。
  • 16位计数器是由THx和TLx两个八位寄存器组成的加1计数器。
  • C/T ̅=1时为技术功能,被计数脉冲由Tx引脚输入。
  • C/T ̅=0时为定时功能,输入脉冲由振荡器(晶振)的12分频提供。
  • 如:12M晶振,提供1MHz脉冲,周期1us。
  • 脉冲和定时器间有控制端()。“1”启动,计数器运行;“0”停止,计数器停止。
  • 单片机通过读取定时器溢出标志(TFx),判断定时器工作状态。
  • 工作步骤:1、设置工作模式(定时器/计数器);2、计算并装入初值;3、启动运行;4、等待溢出。
    2. 定时器相关寄存器
    在这里插入图片描述
  • 单片机中所有的控制和标志都是通过对特定寄存器的读写来实现的。(开关操作:写;TFx状态:读)
  • 定时器工作方式寄存器TMOD(低四位T0/高四位T1):
    (1)GATE:门控位
    0:以TRx来启动定时器/计数器运行。(一般置零
    1:以外部中断和TRx来启动定时器/计数器运行。
    (2)C/T ̅:计数器模式/定时器模式选择位
    0:定时器模式。
    1:计数器模式。
    (3)M1&M0:工作方式选择位
    M1M0=00(方式0):13位定时器/计数器。
    M1M0=01(方式1):16位定时器/计数器。(计数范围大,常用。)
    M1M0=10(方式2):8位常数自动重新装载。(自动重装:溢出清零后自动写入初值,用于串口的波特率发生器。)
    M1M0=11(方式3):T0分为两个8位计数器,T1停止计数。(少用)
  • 控制寄存器TCON(高四位):
    (1)TF1/TF0:计数溢出标志位。
    定时器T0或T1计数溢出时,由硬件自动将此位置置“1”;
    TFx可以由程序查询,也是定时中断的请求源。
    (2)TR1/TR0:计数运行控制位。
    TRx=1:启动定时器/计数器。
    TRx=0:停止定时器/计数器。
    3. 定时器/计数器原理框图
    • 要求:采用定时器0,方式1,实现1ms定时,每隔1ms,P10取反一次,晶振为12MHz(12×〖10〗(-6))。
    • 编程:
      1、确定工作方式,TMOD设置为0001H。
      2、计算初值:(216-x)×(12×〖10〗(-6)÷12)=1×〖10〗^(-3) s,初值x,计数范围2^16。
      可求得:x=65536-1000=64536,化为16进制为FC18,即:TH0=FCH,TL0=18H。
      3、根据需要设置中断。
      4、TR0置位,启动定时/技术器。
      5、反复查询TF0是否为1,判断是否完成定时。
      6、如果定时完成,清除TF0标志,重新装入初值,进行下一轮定时。

5中断

在这里插入图片描述
(查询方式执行)在定时器程序中,当TR0=1时,定时器打开,定时器开始工作,计数器开始+1,但CPU并不知道什么时候定时器溢出。CPU通过不断反复查询TF0状态,判断是否溢出。
响应时间与查询次数之间存在矛盾:响应时间短——查询次数多。
解决办法:中断系统。
在这里插入图片描述

  • 中断的产生:使用哪个中断就打开相应中断开关和总开关。
    中断源:定时中断2个(定时器溢出TF0/TF1)、外部中断2个(TCON低四位:IE0/IE1)、串行中断1个(串口通信部分)。
    中断允许开关:EA—中断总开关;ES—串行中断允许开关;ET1—定时1中断允许开关;EX1—外部1中断允许开关。
  • 中断的响应:
    (中断的方式执行)①设定工作模式、设初值、打开定时器(与查询方式相同);②打开中断总开关、开定时0中断;③不需要反复查询,CPU可以做自己想做的(没事干就while(1));④发生溢出时(产生中断源),程序会自动跳入中断服务子程序void time a () interrupt b:其中,a—0定时器0,a—1定时器1;b—1定时器0,b—0外部中断0,b—2外部中断1, b—3定时器1, b—4串行中断。
  • 好处:避免响应时间与查询次数之间的矛盾,提升程序工作效率;中断方式TF0不需要软件置零,硬件产生完中断后会自动将其置零。
    在这里插入图片描述
#include<reg51.h>
sbit POUT=P1^0;
void main(void)
{
	TMOD=0x01;		//设置工作方式
	TH0=0xfc;		//装初值
	TL0=0x18;
	TR0=1;			//开定时器0
	EA=1;			//开中断总开关
	ET0=1;			//开定时0中断
	while(1);
}
void time0() interrupt 1	//定时器1的中断服务函数
{
	TH0=0xfc;//重新装入初值
	TL0=0x18;
	POUT=!POUT;		
}

6定时与中断应用示例

/***********************************************************
*程序功能:查询方式,定时器工作于方式1,每隔一秒发光二极管闪烁一次。(晶振11.0592M)
***********************************************************/
#include<reg51.h>
#define uint unsigned int
uint pp;
sbit POUT=P1^0;
void main(void)
{
	TMOD=0x01;		//设置工作方式,定时器0,工作模式1(M1=0,M0=1)
	TH0=0xff;		//装初值,定时设置为100us,定时10000次。
	TL0=0xa4;		//对于晶振为11.0592M晶振的单片机最大定时时长只有几十毫秒
	TR0=1;			//开定时器0
	while(1)
	{
		if(TF0==1)	//单片机反复查询定时器0的溢出标志位TF0
		{
		TF0=0;
		pp++;		//每定时一次PP+1
		TH0=0xff;//重新装入初值
		TL0=0xa4;
		}
		if(pp==10000)
		{
		POUT=~POUT;
		pp=0;
		}		
	}
}
/***********************************************************
*程序功能:中断方式,定时器工作于方式1,每隔一秒发光二极管闪烁一次。(晶振11.0592M)
***********************************************************/
#include<reg51.h>
#define uint unsigned int
uint pp;
sbit POUT=P1^0;
void main(void)
{
	TMOD=0x01;		//设置工作方式,定时器0,工作模式1(M1=0,M0=1)
	TH0=0xff;		//装初值,定时设置为100us,定时10000次。
	TL0=0xa4;		//对于晶振为11.0592M晶振的单片机最大定时时长只有几十毫秒
	TR0=1;			//开定时器0
	EA=1;			//开总中断
	ET0=1;			//开定时器0中断
	while(1)
	{
		if(pp==10000)
		{
		POUT=~POUT;
		pp=0;
		}		
	}
}
void time0() interrupt 1
{
	pp++;		//每定时一次PP+1
	TH0=0xff;//重新装入初值
	TL0=0xa4;
}	
/***********************************************************
*程序功能:外部中断方式,定时器工作于方式1,每隔一秒发光二极管闪烁一次。(晶振11.0592M)
***********************************************************/
#include<reg51.h>
sbit	LED1=P0^0;
sbit	LED2=P0^1;
void ISR0(void) interrupt 0 //外部中断0服务函数
{
	LED1=~LED1;
}
void ISR1(void) interrupt 2 //外部中断1服务函数
{
	LED2=~LED2;
}
void main(void)
{
	IP=0x05;	//外部中断0和外部中断1设置为高优先级
	IT0=1;		//外部中断0为下降沿触发(中断引脚P3.2输入下降沿信号时引发中断)
	IT1=1;		//外部中断1为下降沿触发(中断引脚P3.3输入下降沿信号时引发中断)
	EX0=1;		//开外部中断0
	EX1=1;		//开外部中断1
	EA=1;		//开中断总开关
	while(1);
}

7数码管

  • 静态数码管
    在这里插入图片描述
    共阴&共阳两种数码管,公共端分别接地/VCC,A-H引脚分别接单片机I/O口。
    在这里插入图片描述
    共阴数码管数组定义0-F显示码:a
    unsigned char code LED7code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
    0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
    在这里插入图片描述
  • 动态数码管
    位控端:控制哪个数码管亮;段控端:控制单个数码管显示。
    位控端使几个数码管轮流显示,由视觉暂停效应使得视觉上多个数码管是同时点亮的。
    在这里插入图片描述
    由于单片机I/O口输出电流是有限的,位控端连接七个LED需要三极管放大。
    在这里插入图片描述
/*************************************************************
*程序功能:静态数码管,数码管轮流显示0-F
*************************************************************/
#include<reg51.h>
unsigned char code LED7code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//数组,定义0-F显示码
void delay(void)
{
	unsigned int i;
	for(i=0;i<65000;i++);
}
void main(void)
{
	unsigned char i;
	P2=0xfe;			//
	while(1)
	{
		for(i=0;i<16;i++)//16个内容循环显示
		{
		P0=LED7code[i];//P0口连接数码管A-H
		delay();
		}
	}
}
/*************************************************************
*程序功能:数码管动态显示
*************************************************************/
#include<reg51.h>
unsigned char code wei[]={~0x08,~0x04,~0x02,~0x01};//数码管各位码表
unsigned char code duan[]={0xc0,0xf9,0xa4,0xb0};//0-3码表
void delay(unsigned int i)
{
	unsigned int m,n;
	for(m=i;m>0;m--);
		for(n=90;n>0;n--);
}
void main(void)
{
	unsigned char num;			
	while(1)
	{
		for(num=0;num<4;num++)
		{
		P2=	wei[num];
		P0=duan[num];
		delay(20);
		}
	}
}

8串口

计算机与外设/计算机与计算机之间的通信:并行通信、串行通信。
在这里插入图片描述

  • 并行通信:把所有的数据端连在一起一次处理,如8位计算机一次处理8个位的数据,需要询问(WR) ̅、应答(RD) ̅、8根数据线A0-8地址端/D0-8数据端。(优缺点)速度快;但是硬件连接复杂。
    在这里插入图片描述
  • 串行通信:数据分时通过同一通道传输。(优缺点)传输速度慢;硬件简单,最多只需要2根线RXD接收端/TXD发送端。
    在这里插入图片描述
  • 串行通信的三种方式:单工(A->B)、半双工(A->B|B->A)、全双工(A->B&B->A)。单片机是全双工异步通信方式。
    在这里插入图片描述
  • 异步串口通信帧格式:起始位(由1—0,下降沿)一个数据是10/11位(区别在于奇偶校验位)串口方式1(10位一帧)无校验位,低位在前(读数时从后往前读D7-0)。
    在这里插入图片描述
    波特率:设置正确的波特率才能收到正确的数据。
    在这里插入图片描述
  • 串口的相关寄存器:
    1、串行数据缓冲器SBUF:
    在这里插入图片描述
    2、串行控制寄存器SCON:
    在这里插入图片描述
    RI—接收中断标志位;TI—发送中断标志位;
    RB8/TB8—接收及发送数据第9位(奇偶校验位);
    REN—接收控制(0:禁止;1:允许);
    SM2—多机通信(0:双机;1:多机);
    SM1/SM0—串行口工作方式选择:
    方式0,同步移位寄存器输入/输出,波特率固定为fosc/12;
    方式1,10位异步收发,波特率可变(T1溢出率/n,n=32/16);
    方式2,11位异步收发,波特率固定为fosc/n,n=32/16;
    方式3,11位异步收发,波特率可变(T1溢出率/n,n=32/16)。
/*************************************************************
*程序功能:串口发送Hello
*************************************************************/
#include<reg51.h>
#include<stdio.h>	//输入输出函数头文件
void main(void)
{
	SCON=0X50;	//串口方式1允许接收
	TMOD=0X20;	//定时器1定时方式2
	TH1=0XF4;	//11.0592M	2400波特率
	TL1=0xF4;
	TI=1;		//串口发送标志
	TR1=1;		//启动定时器
	
	while(1)
	{
		printf("Hello world!\r\n");//字符串输出到串口
	}
}
/**************************************************
*串口通信实验:发送
**************************************************/
#include<reg51.h>
#include<stdio.h>	//输入输出函数头文件
unsigned char code MESSAGE[]="My first serial data!\n";
unsigned char a;
void delay(unsigned int i)
{
	unsigned char j;
	for(i;i>0;i++)
		for(j=200;j>0;j--);
}
void main(void)
{
	SCON=0X50;	//REN=1允许接收状态 串口方式1
	TMOD|=0X20;	//定时器1定时方式2
	TH1=0XF4;	//11.0592M	2400波特率 数据位8 停止位1
	TL1=0xF4;
	TI=1;		//串口发送标志
	TR1=1;		//启动定时器
	
	while(1)
	{
		a=0;
		while(MESSAGE[a]!='\0')	//数组最后一个位为'\0'
		{
			SBUF=MESSAGE[a];	//SBUF接收/发送缓冲器(串行通信特殊功能寄存器)
			while(!TI);			//等待数据传送(TI发送中断标志) TI=1时说明数据发送完成
			TI=0;				//清除数据传输标志
			a++;				//下一个字符
		}
		delay(1000);
	}
}
/**************************************************
*串口通信实验:收发(数据转发功能:单片机收到了电脑发送的数据后又转发回给电脑)
**************************************************/
#include<reg51.h>
#define uchar unsigned char
uchar a,flag;				//设置全局变量
void main()
{
	SCON=0X50;	//REN=1允许接收状态 串口方式1
	TMOD=0X20;	//定时器1定时方式2
	TH1=0XF4;	//11.0592M	2400波特率 数据位8 停止位1
	TL1=0xF4;
	TI=1;		//串口发送标志
	TR1=1;		//启动定时器
	EA=1;		//开总中断
	ES=1;		//开串中断
	while(1)
	{
		if(flag==1)		//如果有数据则进入这个语句
		{
			ES=0;		//进入发送数据时先关闭串行中断
			flag=0;
			SBUF=a;		//将数据原样发回
			while(!TI);	//等待数据发完
			TI=0;
			ES=1;		//退出再开串行中断
		}
	}
}
void serial() interrupt 4//串行中断函数
{
	a=SBUF;				//将收取的数据存到a
	flag=1;				//标志置位——表示单片机收到数据
	RI=0;				//接收标志清零
}

9RS232接口

  • RS232接口标准:
    在这里插入图片描述
    RS232最常用的就是2-RXD、3-TXD、5-GND。
    注意:在传输距离近的情况下(距离<1m),单片机和电脑可以直接通过TTL的线连接进行通信;连接线过长时,由于(单片机输出都是TTL信号)TTL电压比较低衰减比较厉害,可以转换(MAX232/220/202芯片)为232的方式进行传输(15m以内传输没问题,速率较低时采用双绞线传输距离还可以更长30-35m)
    在这里插入图片描述
    在这里插入图片描述
    RS232的连接:连接线有直通线&交叉线
    在这里插入图片描述
    易损坏,不支持热拔插,带电不要拔插。
2019-06-27 16:50:57 huigeyu 阅读数 656
  • 《C语言基础》 之 第9章 字符串

    课程内容:字符数组1、字符串越位的问题、指针变量的空间大小、字符串常量、字符串传参、printf格式化输出字符串、字符串的非格式化输出函数、字符串输入函数、strlen函数、strcpy函数和strncpy函数、strcmp函数和strncmp函数、strcat函数和strncat函数。

    3512 人正在学习 去看看 张先凤

之前对串口各模块的设计都做了相关介绍。这里介绍串口屏的相关知识。

本次项目使用的串口屏型号是陶晶驰串口屏TJC3224T024_011,这个型号的串口屏的资料在官网可以找到。本文抛转引玉,简单介绍以便在本工程中更好的应用。

下图是该串口屏的实物图:

一般地,使用单片机或者嵌入式MCU控制串口屏,都会用到串口,同样地,在FPGA中实现也是类似,不过稍微复杂,具体代码设计过程中有以下问题需要注意。

 

Q1:FPGA向HMI发送命令,要使HMI中的某个文本控件显示相应的数据,该如何操作呢?

ASR:根据HMI指令集,串口屏的指令数据为字符串数据格式,如文本控件t0,其内容属性txt,t0.txt表示文本控件的内容,当要改变t0的内容时,需要发送以下字符串命令:t0.txt="123"(整个指令就是一个字符串),当时用单片机串口发送时,需要执行以下程序,如:

Serial.print("t0.txt=\"你好\"");
Serial.write(hexEND,3);

从中清楚看到,整条代码为一条字符串数据,而其属性txt属于字符串属性,所以要加上双引号,故有以上写法——整个括号内由两对双引号

在单片机C语言中," "表征这是一条字符串数据,并不需要考虑使用串口发送时是否会发送",因为在串口助手中,当以文本模式发送数据时,是默认不用用户自己加入" "的,同理在发送字符串时,总是会冠以" ",如使用sprintf,或者直接使用串口发送函数直接发送Serial.print(“a good boy!”)。

 

Q2:前面介绍了HMI的字符串指令,所以,使用FPGA发送字符串时是否要把最外面的双引号(表征字符串属性的双引号)发送出去呢?

回答:不需要,这只是表征这条数据是字符串数据,实际发送中不需要将其作为有效字符发送。同理,字符串结尾标识\0也不需要对外发送。故,如果需要在文本控件t0中显示123,只需要发送t0.txt=”123””12个字符;当然,该类型串口屏的结束指令命令是发送HEX的FF FF FF,所以,发送完第一条指令后,在其后再发送FF FF FF即可(16进制,3个)。所以用户书写指令代码时不必考虑过多,而只需关注所发送的字符串的内容即可。

NOTE数据指令和结束指令最好间隔开,因为这实际是两条指令,在使用ascii码表示时,两条指令可能会合并成一条数据,即t0.txt=”123””FF FF FF,这样理解的话,则指令格式不完全(没有明确的指令结束标志,当然,如果接受到第二个’”就自动识别为第一个指令那就ok,但实际并不清楚)。

整个串口屏的verilog代码设计,就是简单地通过串口发送指令在文本控件中显示相应的数据。有关串口屏幕内容的上位机设计,比较简单,这里不做过多介绍,网上可以找到教程。

到此,整个FPGA控制USART_HMI显示数据的工程就介绍完毕了。

没有更多推荐了,返回首页