2019-03-14 20:20:33 Easadon 阅读数 389
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6018 人正在学习 去看看 朱有鹏

 串口的知识点比较多,还是需要自己去多了解一下,在这里我就直接上一个简单的例子,供大家学习理解:

/***********************************************
* 本代码实现的是:	 
*1.串口接收到0~f字符可以在数码管第一位显示		       
*2.若按下独立键盘K1-K4,可分别向串口发送字符1-4		                     
**********************************************/   

#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int

sbit duan = P2^6;
sbit wei = P2^7;
sbit K1 = P3^4;
sbit K2 = P3^5;
sbit K3 = P3^6;
sbit K4 = P3^7;

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                        0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};	 

uchar dat='g';
void delay(unsigned char i)
{
	unsigned char j,k;
  for(j=i;j>0;j--)
    for(k=112;k>0;k--);
}

void display(unsigned char a)
{
	uint b;
	P0 = 0;
	duan = 1;
	duan = 0;
	if(a >= 'a' && a <= 'g')
	{
		b = a - 'a' + 10;
	}
	else
	{
		b = a - '0';
	}
	P0 = table[b];
	duan = 1;
	duan = 0;
	P0 = 0xfe;
	wei = 1;
	wei = 0;
}
void Uartinit()
{
	EA = 1;
	ES = 1;
	TMOD = 0x20;
	SCON = 0x50;
	PCON = 0x00;
	TH1 = 0xfd;
	TL1 = 0xfd;
	TR1 = 1;
}
void main()
{
	Uartinit();
	while(1)
	{
		display(dat);
		if(K1 == 0)
		{
			dat = '1';
			SBUF = dat;
			while(!TI);
			TI = 0;
		}
		if(K2 == 0)
		{
			dat = '2';
			SBUF = dat;
			while(!TI);
			TI = 0;
		}
		if(K3 == 0)
		{
			dat = '3';
			SBUF = dat;
			while(!TI);
			TI = 0;
		}
		if(K4 == 0)
		{
			dat = '4';
			SBUF = dat;
			while(!TI);
			TI = 0;
		}
	}
}
void Uart() interrupt 4
{
	dat = SBUF;
	RI = 0;
}

 

2019-08-08 21:51:23 ydb1358396458 阅读数 146
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6018 人正在学习 去看看 朱有鹏

 

写了个串口通讯的小例子,点击右侧链接查看 https://github.com/PuGongYing1/SerialPort

 

很少看到有资料写如何以中断的方式发送一帧数据,如果以等待的发送数据帧,对高速运行的单片机来说是很浪费时间的,下面就介绍一种使用中断方式发送数据帧,操作平台采用51 mcu

首先定义一个数据帧的结构体,该结构体可以做为一个全局变量,所有的发送都要经过这个结构体:

//结构体
struct {
        char busy_falg;//忙标志,若在发送数据时置位1,即在开始发送置位1,发送结束置位0
        int index;//索引,指向需要发送数组的位置
        int length;//整个数据帧的长度
        char *buf;//指向需要发送的数据帧,建议为全局变量,否则一旦开始发送,必须等到发送结束,即判断busy_falg为0
} send_buf;发送数据的函数,这里有个缺点,就是还是要使用while来检测串口是否忙碌,不过这样比占用系统时间来发送要好的多了:

//发送一帧
void SendBuf(char *buf,int length)
{
        while(busy_falg);//查询发送是否忙,否则循环等待
        send_buf.length = length;
        send_buf.index = 0;        
        send_buf.buf = buf;
        send_buf.busy_falg = 1;
        SBUF = send_buf.buf[0];//写入SBUF,开始发送,后面就自动进入中断发送
}串口中断发送函数,注意设置空闲标志位,避免多任务时多个发送帧调用了同一个结构体:

void SerialInt() interrupt 4     //串口中断
{  
    if(RI == 1)  //串口接收
    {  
        RI = 0;  
    }  
        else if(TI == 1)//串口发送
        {
                TI = 0;
                send_buf.index++;
                if(send_buf.index == send_buf.length)
                {
                        send_buf.busy_falg = 0;//发送结束
                        return;
                }
                SBUF = send_buf.buf[send_buf.index];//继续发送下一个
        }
          

串口中断发送就是这样简单,注意busy_falg和index的使用。
 

From <http://m.blog.csdn.net/liucheng5037/article/details/48831993>

 

2018-11-11 20:24:53 add991004 阅读数 4815
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6018 人正在学习 去看看 朱有鹏

其实这是个51单片机串口通信的小例子,课堂上老师说你们可以去尝试弄一下,于是就去网上找一下资料,就做了这个实验。

先把一个作为主机,用来发送数据;另一个作为从机,用来接收数据。将两个程序各自烧录到对应的板子上去,并将主机的TX(P3.0)接到从机的RX(P3.1),主机的RX(P3.1)接到从机的TX(P3.1),便可以实现将主机的数据发送到从机上去,并在从机上实现功能,这时可以看到从机上流水灯的现象

主机发送代码

#include<reg51.h>
unsigned char code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};           //流水灯控制码
void send(unsigned char dat)            //数据发送程序
{
   	SBUF=dat;                           //将要发送的数据存入发送缓冲器中
	while(TI==0);                       //若发送中断标志位没有置1(正在发送数据),就等待
	TI=0;                               //若发送完成,TI自动置1,这里把它清零
}
void delay(void)                        //延时函数
{
	unsigned char m,n;
	for(m=0;m<200;m++)                  //延时约50ms
	for(n=0;n<250;n++);
}
void main(void)
{
	unsigned char i;
	TMOD=0x20;                         //定时器T1工作于方式2(可自动重装的8位定时器)
	SCON=0x40;                         //串口工作方式1,不允许接收
	PCON=0x00;                         //波特率不倍增
	TH1=0xf4;                          //波特率为2400b/s
	TL1=0xf4;
	TR1=1;                             //启动定时器T1(T1作波特率的发生器)
	while(1)
	{
		for(i=0;i<8;i++)               //一共8位的流水灯控制码
		{
			send(tab[i]);              //发送数据
			delay();                   //每50ms发送一次数据
		}
	}
}

从机接收代码

#include<reg51.h>
unsigned char receive(void)         //数据接收函数
{
	unsigned char dat;
	
	while(RI==0);                   //数据没有接收完毕时等待接收
	RI=0;                           //接收完毕时清零
	dat=SBUF;                       //将接收缓冲器中的数据存入dat
	return dat;                     //将接收到的数据返回
}
void main(void)
{
	TMOD=0x20;                     //设置定时器T1工作于方式2
	SCON=0x50;                     //串口工作方式1,允许接收数据
	PCON=0x00;                     //波特率不倍增
	TH1=0xf4;                      //波特率为2400b/s
	TL1=0xf4;
	TR1=1;                         //启动定时器T1
	REN=1;                         //允许接收数据
	while(1)
	{
		P2=receive();              //将接收到的数据送到P1口显示	
	}
}

主机硬件连接如图

从机硬件连接如图

 

2018-10-26 20:49:48 abcvincent 阅读数 1611
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6018 人正在学习 去看看 朱有鹏

工业控制中单片机与pc机通讯,常常通过串口通讯来完成,本次基于RS232通讯来完成的,硬件是普中的STC51单片机开发板;板子如下图:

不需要液晶显示器,自带的例子这里就不贴了,主要实验是Qt进行串口链接,发送数据,单片机判断发送的内容并做出反馈;

单片机程序是c语言写的,用keil编译,再下载到开发板上的,单片的程序如下:

#include<reg51.h>
//--声明全局函数--//
void UsartConfiguration();
unsigned char To[]=" THE END ";
unsigned char ToNo[]=" Timeout ";
unsigned char GET[5];
unsigned int i,j,n,flag;
unsigned char receiveData;
unsigned char AA[]="?!";
void Delay10ms(unsigned int c);   //延时10ms

void main()
{
	UsartConfiguration();
	flag=0;//标记为0;为1时候发送" THE END ",当然不用flag直接在中断函数里写也可以

	while(1)
	{

/////////////用flag时取消注释//////////////////////
//		 if(flag==1)
//		 {
//			for(i=0;i<9;i++)
//			{
//		    	ES=0;
//				SBUF=To[i];
//				while(!TI);		  //等待发送数据完成
//				TI=0;
//		     }
//			 ES=1;
//			 flag=0;		
//			}
	}
}
/*******************************************************************************
* 函 数 名         :UsartConfiguration()
* 函数功能		   :设置串口
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void UsartConfiguration()
{
	SCON=0X50;			//设置为工作方式1
	TMOD=0X20;			//设置计数器工作方式2
	PCON=0X80;			//波特率加倍
	TH1=0XF3;		    //计数器初始值设置,注意波特率是4800的
	TL1=0XF3;
	ES=1;						//打开接收中断
	EA=1;						//打开总中断
	TR1=1;					    //打开计数器
}

/*******************************************************************************
* 函 数 名         : Usart() interrupt 4
* 函数功能		   : 串口函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Usart() interrupt 4
{		
	unsigned char ff[]="/";
    RI=0;
    receiveData=SBUF; //出去接收到的数据
	SBUF=receiveData; //将接收到的数据放入到发送寄存器
	while(!TI);		  //等待发送数据完成
	TI=0;			  //清除发送完成标志位

	if(receiveData==ff[0])	//如果收到"/",flag设置为1,则发送" THE END " ,并且解析指令并执行某种操作
			{
			SBUF=AA[1];
			flag=1;
			while(!TI);		 //等待发送数据完成
			TI=0;			 //清除发送完成标志位
				
////////////////用flag时候注释下面///////////////////////
				for(i=0;i<9;i++)
			{
                ES=0;          //关闭接收中断
                SBUF=To[i];	   //循环发送字符
                while(!TI);	   //等待发送数据完成
                TI=0;
		     }
			 ES=1;	   //打开接收中断
///////////////////////////////////////
			}
}

基本功能如上面的注解,收到“/”时候,说明pc端发送完成,则单片机反馈给pc信息;

qt的程序如下,不过先建一个窗口,然后在窗口里添加控件,然后再把功能写进控件,窗口程序如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //设置下拉菜单,波特率
    ui->comboBox_2->addItem("1200");
    ui->comboBox_2->addItem("2400");
    ui->comboBox_2->addItem("4800");
    ui->comboBox_2->addItem("9600");
    ui->comboBox_2->addItem("19200");
    ui->comboBox_3->addItem("8");
    ui->comboBox_4->addItem("0");
    ui->comboBox_5->addItem("1");
    ui->comboBox_5->addItem("2");

    //设置波特率下拉菜单默认显示第0项
    ui->comboBox_2->setCurrentIndex(2);

    //查找可用的串口
    foreach (const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        QSerialPort serial;
        serial.setPort(info);
        if(serial.open(QIODevice::ReadWrite))
        {
            ui->comboBox->addItem(serial.portName());
            serial.close();
        }
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    if(ui->pushButton->text()==tr("打开串口"))
    {
      serial=new QSerialPort;
      serial->setPortName(ui->comboBox->currentText());//设置串口名称
      serial->open(QIODevice::ReadWrite);//打开串口

      //设置波特率
//      serial->setBaudRate(QSerialPort::Baud4800);
      switch (ui->comboBox_2->currentIndex())
      {
      case 0:
          serial->setBaudRate(QSerialPort::Baud1200);
           break;
      case 1:
          serial->setBaudRate(QSerialPort::Baud2400);
           break;
      case 2:
          serial->setBaudRate(QSerialPort::Baud4800);
           break;
      case 3:
          serial->setBaudRate(QSerialPort::Baud9600);
           break;
      case 4:
          serial->setBaudRate(QSerialPort::Baud19200);
          break;
      default:
          break;
      }

     //设置校验位
      switch (ui->comboBox_4->currentIndex())
      {
      case 0:
          serial->setParity(QSerialPort::NoParity);
          break;
      default:
          break;
      }
      //设置停止位
      switch (ui->comboBox_5->currentIndex())
      {
      case 1:
          serial->setStopBits(QSerialPort::OneStop);//停止位设置为1
           break;
      case 2:
          serial->setStopBits(QSerialPort::TwoStop);//
          break;
      default:
          break;
      }

      //设置流控制
      serial->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制
      ui->comboBox->setEnabled(false);
      ui->comboBox_2->setEnabled(false);
      ui->comboBox_3->setEnabled(false);
      ui->comboBox_4->setEnabled(false);
      ui->comboBox_5->setEnabled(false);
      ui->pushButton->setText(tr("关闭串口"));


    }
    else
    {
        //关闭串口
        serial->clear();
        serial->close();
        serial->deleteLater();

        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(true);
        ui->comboBox_3->setEnabled(true);
        ui->comboBox_4->setEnabled(true);
        ui->comboBox_5->setEnabled(true);
        ui->pushButton->setText(tr("打开串口"));
    }

    //连接信号槽
    QObject::connect(serial,&QSerialPort::readyRead,this,&MainWindow::ReadData);
}

//读取接收到的信息
void MainWindow::ReadData()
{
    QByteArray buf; //二进制
    buf=serial->readAll();
    if(!buf.isEmpty())
    {
        QString str=buf;
        if(str.endsWith(" THE END "))
        {
            ui->textEdit->append("I get");
        }
        ui->textEdit->append(str);
    }
    buf.clear();
}

//发送按钮槽函数
void MainWindow::on_pushButton_2_clicked()
{

    if(ui->pushButton->text()=="关闭串口")
    {

        serial->write(ui->lineEdit->text().toLatin1().append("/"));//Latin1是ISO-8859-1的别名,单片机仅能识别ASCII码
//                     serial->write(ui->lineEdit->text().toLatin1());//Latin1是ISO-8859-1的别名,单片机仅能识别ASCII码

       ////////////////////////test////////////////////////////////
        //        QString tmp=ui->lineEdit->text().toUtf8();
        //        qDebug() <<"utf8: "<<tmp ;
        //        qDebug() <<"toLatin1(): "<<tmp.toLatin1() ;
        //        qDebug() <<"toLocal8Bit(): "<<tmp.toLocal8Bit()  ;
        //        qDebug() << ui->lineEdit->text().toLatin1() ;
        ////////////////////////////////////////////////////////


        ui->lineEdit->clear();
    }
    else
    {
        ui->pushButton_2->setEnabled(true);
        QMessageBox::about(NULL, "提示", "串口未打开");
    }

}

效果如下:

因为串口只能手动ASCII,中文无法识别;所以要发送中文就是乱码;

 

2018-10-23 20:43:00 zj490044512 阅读数 11269
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6018 人正在学习 去看看 朱有鹏

在进行串口的收发数据过程中一定要注意波特率的问题。

大多数51单片机用的都是11m晶振而只有少部分用的是奇葩的12m(楼主的就是),在12m晶振进行串口通信时切忌要将波特率设置为4800以下,应为12m晶振的波特率在9600以上误差很大容易丢失数据,动手能力强的可以折腾一下用定时器输出9600波特率。

至于,串口中断以及波特率的设置可以参考网上例子忒多。

在用串口助手进行串口收发数据时都会触发串口中断并且在发送数据时只能够一位一位的发送,也就是SBUF=10是不行的智能一位一位发送也就是每次只能发送(0-9或者一个字符)并且串口调试助手接收到的数据是asii码要进行下转换,发送也要进行一下转换。这只是针对串口调试助手

话不多说直接上代码:

 

由于代码不方便公布所以只能上图片需要的可以私聊博主

 

 转载请标明原贴出处:https://blog.csdn.net/zj490044512

串口通信二

阅读数 742

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