当前位置:首页 > 串口
  • 51单片机学习单片机之路总结

    51单片机学习单片机之路总结

    学习单片机有一学期了,现在也由51转到STM32了。一直想对51的学习做一个总结。也希望对别人有一些启发。也给后学者提供一些建议。当然本文是我对自己学习过程的总结,若有不对的地方,还请高手指出。 我想,再看本文之前,最好对单片机有了最基础的了解,最好能用单片机驱动起一个LED灯,否则,可能会不知所云。 首先我想问一个问题,你认为单片机有哪些内容呢?也许你现在手里有一块开发板,你已经开始从流水灯开始,一个一个外设在跑了。也许你已经看过一些单片机入门的书了。如果是这样,我估计你会回答,单片机包括了流水灯,键盘,数码管,定时器,中断,串口,AD,DA,液晶,DS18B20……其实这样的回答其实符合了大多数初学者的心态。因为天祥老师的视频也是这么教的。但是当你会操作流水灯,键盘,数码管,液晶,你有没有发现他们有一个共同点,就是都是通过I/O口输出或检测高低电平来驱动这些外设,那我们可不可以把这些模块归为一类,就叫I/O口操作呢,那么这样,要学的内容就又被浓缩了一下,可分为四个模块了,I/O口,定时器,中断,串口。对于AD,有的单片机,例如**公司的加强型单片机就自带了AD,若使用AD芯片,则也属于I/O部分,AD部分我放到后面再提。 这样,学起来条理就清楚了,其实当你驱动了流水灯和按键模块。可以说,你就完成第一部分,I/O口的学习了。I/O的输入和输出你都学会了。至于数码管,液晶,那是为了加强你I/O口编程的能力,说来说去,就是在什么时间输出高电平,什么时间输出低电平以符合他们的通信协议而已。如果你能理解他们都是I/O操作,学起来这些是很简单的。 接下来,继续定时器,中断的学习,无所质疑,定时器与中断是分不开的,没有中断,定时器也很难实现功能。在这里,建议先学习外部中断,如果你认真的学完外部中断,我想你应该能深刻了解中断的含义(这里插一句,一定要理解中断,为后来更高级处理器的中断系统打基础),在学定时器与定时器中断。如果你能深入学习定时器与定时器中断,我想这是,你应该能用数码管做一个电子钟了,具体实现就看你的编程水平了,可以试一试哦。 然后,花一把功夫学完串口通信,我可以对你说,你把单片机的内容学完了。现在,你可以试着把这些分立的模块组合做成一个实际的东西巩固一下。这时,但是,你要知道,还有更多的事等着你。现在只是基础,你前面学的是单片机自身的内容,这时,你需要去了解单片机的外围设备了,例如AD,DA,I2C,SPI等等内容了。但是,有些单片机自带了AD的功能,但我仍然不把他列入单片机自身的内容,包括PWM,也不属于单片机的内容,尽管有些单片机带这个功能。这些外设还是需要花大气力研究的,学到这里,你应该很容易读懂芯片的时序图了,也就是协议。这时对于DS18B20,红外,315M无线通信等等,应该都不在话下了。 你原先的程序都是在开发板上跑的,你现在可以学习如何自制电路板了,也就是学会画板,推荐使用Altium Designer软件。现在可以自己画一块系统板,做出来,看看能不能工作。如果不能,找找原因,可以跟你说,这个是必须要会的。至此,单片机学的差不多了。 但是,更高的目标还在等着你,因为,一开始就是用C语言在编程,对底层的认识比较浅薄的,你可以看一看单片机的汇编语言,不要求你会写汇编,但至少你要能看懂别人的汇编代码,你可以接触一下底层寄存器到底是怎么工作的,怎么寻址的。在这里插一句,以前你写代码时第一句总是#include,我想如果把这一句去掉,你还能让编译通过吗?你理解这个文件里有哪些内容吗,把这个文件里的定义弄明白了,51单片机的寄存器也就差不多了。这时,你应该熟悉了51单片机了。这时学习其他单片机也应该很简单了,只是换一种编译器,寄存器改了而已,原理是不变的,反正都是用C语言编程,只要稍微改一下就完全可以适应另一种芯片。这就是我的整个学习过程,仅供参考。 这时,你需要的就是培养单片机的开发经验。这时,不能说你精通了单片机,只能说会用单片机了。我想问一句,这时,你可以开发一个仓库多点温度测控系统,数据传回电脑并处理吗?不能,我也不能,但是如果你花大学四年时间就搞51的话,我确定是可以的。在这里就涉及到一个方向选择问题,关于方向选择,我的学长张永翔给了我比较好建议,这时你有两个方向,一个往低层做,就是继续学习51单片机开发,你的目标就是用最简单的芯片,最低的成本实现最复杂的系统,比的是成本,也就是说,实现同样功能的系统,你可以用比别人更低的成本,更简单的硬件,更高效的算法去完成,这样你才有市场。另一个当然是往高层做,去学习更高级的单片机,学习ARM嵌入式,操作系统,不过这条路比前一条难很多,当然就业的报酬也很多。只是,你要花更多的时间以及更高的投资,ARM开发板等等,这可不是一笔小数目,你要花的起,当然,从文章的第一句就知道了,我选的是后者。其实我觉得,作为本科生,还是选择后者比较好,回旋余地大,可以继续考研的。我现在还记得我的电路分析老师说的一句话,“现在学电子的本科生,如果你毕业时只会一个单片机,你就废了”,我觉得还是挺有道理的,作为本科生,尤其是电子专业的本科生,往高层做是必须的,而且随着技术的发展,高级单片机例如STM32的成本也一直在下降,高级单片机的普及已成为一种趋势了。 当然,这只是个人的理解,仁者见仁,智者见智。若有不同见解,欢迎讨论。再次重申,本文系个人的总结,若有不对的地方,请指正。

    时间:2021-03-02 关键词: 51单片机 STM32 串口

  • 单片机串口如何接收不定长数据的?

    单片机串口如何接收不定长数据的?

    我们在使用其他STM32的单片机的时候,会发现有些困难,会发现常用的方法并不能用,在还没有接收完数据的时候,就解决不了。于是,只能用通用的方法来解决了。 这个通用的方法,其实原理和使用IDLE的原理一样:接收完一个字节以后,如果超过了一定的时间,就认为是接收完一帧数据了。首先我们要知道,串口是接收一个字节,就会发生一次中断,如果一帧数据包含10个字节,就会发生10次中断。在接收一个字节以后,会紧跟着接收下一个字节,如果时间超了一定值,就代表一帧数据已经发完了。 下面,我分别用STM32和51单片机的代码来演示一下这个通用代码的实现。 1、STM32(以STM32L0系列为例) 串口中断函数: 2、51单片机(以STC8系列为例) 串口中断函数: void UART1_Isr() interrupt 4 // 串口中断服务函数 { if(RI) // 如果接收到一个字节 { RI = 0; // 中断标志位清0 Res_Buf[Res_Count++]=SBUF; // 把数据保存到接收数组 Res_Sign=1; // 表示已经接收到数据 Res_Times=0; // 延时计数器清0 } } 3、在主函数中处理串口数据 if(Res_Sign==1) // 如果串口接收到数据 { //延时等待接收完一帧数据 do{ Res_Times++; // 延时计数器+1 HAL_Delay(1); // 延时1ms }while(Res_Times<5); // 5ms时间到 //////////// //这里就可以处理接收数据了 //////////// Res_Sign=0; // 接收标志清0 Res_Count=0; // 接收数据字节计数器清0 } 4、程序解释 程序里面有4个全局变量,分别是: unsigned char Res_Buf[256]; //接收数据的数组,用来接收串口数据 unsigned char Res_Count=0; //接收数据的字节计数器,表示本次一帧数据包含几个字节 unsigned char Res_Sign=0; //接收到数据标志,接收到1个字节就会置1 unsigned char Res_Times=0; // 延时计数器,用来判断有没有接收完一帧数据 在串口中断函数里面,每接收到一个字节,就会把接收到的字节保存到Res_Buf数组中,同时,字节计数器+1。然后把Res_Sign置1,表示已经接收到串口数据,但是,有没有接收完,是不一定的。在主函数当中,发现这个变量等于1了,就开始启动延时计数Res_Times,让这个变量++,只要延时到了5ms,就表示接收完一帧数据,退出do while后就可以开始处理数据了,但是,当接收到第二个字节以后,会在中断函数里面把Res_Times清0,也就是说,主函数里面的Res_Times++以后,白加了,只要有数据还没有接收完,这个Res_Times就会一直清0,如果串口接收能接收一万年也接收不完一帧数据,那一万年,Res_Times也到不了5。只有当再也没有串口数据过来了,Res_Times才会加到5,然后退出do while,表示接收完一帧数据了,可以开始处理了。 上面的方法,适合所有的单片机。方法好不好,主要看自身产品的需求,适合就好,不适合就不好。方法有多种,根据你的需求调整到最好,就可以。

    时间:2021-02-27 关键词: 单片机 串口

  • 如何利用STM32串口接收不定长数据

    如何利用STM32串口接收不定长数据

    我们在平时操作中,我们会遇到STM32单片机带IDLE中断,这个时候我们不必慌张,其实我们是可以利用这个中断的,不只是STM32单片机,其他的ARM单片机也可以用下文介绍的方法。 首先介绍一下IDLE中断什么时候发生: IDLE就是串口收到一帧数据后,发生的中断。什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据。 如何判断一帧数据结束,就是我们今天讨论的问题。因为很多项目中都要用到这个,因为只有接收到一帧数据以后,你才可以判断这次收了几个字节和每个字节的内容是否符合协议要求。 看了前面IDLE中断的定义,你就会明白了,一帧数据结束后,就会产生IDLE中断。这个中断真是太TMD有用了。省去了好多判断的麻烦。 如何配置好IDLE中断? 下面我们就配置好串口IDLE中断吧。 这是串口CR1寄存器,其中,对bit4写1开启IDLE中断,对bit5写1开启接收数据中断。(注意:不同系列的STM32,对应的寄存器位可能不同) (RXNE中断和IDLE中断的区别? 当接收到1个字节,就会产生RXNE中断,当接收到一帧数据,就会产生IDLE中断。比如给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断。) 这是状态寄存器,当串口接收到数据时,bit5就会自动变成1,当接收完一帧数据后,bit4就会变成1. 需要注意的是,在中断函数里面,需要把对应的位清0,否则会影响下一次数据的接收。比如RXNE接收数据中断,只要把接收到的一个字节读出来,就会清除这个中断。IDLE中断,如何是F0系列的单片机,需要用ICR寄存器来清除,如果是F1系列的单片机,清除方法是“先读SR寄存器,再读DR寄存器”。(我怎么知道?手册上写的) 下面以STM32F103为例给出源程序。 我们先来看程序中的主要部分。 串口初始化函数片段 如果你原来的串口初始化函数具有打开串口接收中断的话,实际上就是在初始化函数中多了一条打开空闲中断的语句。 串口中断函数 串口中断函数里面,最重要的两条语句,就是上图中圈出来的两条语句。第一条语句用来判断是否接收到1个字节,第二条语句用来判断是否接收到1帧数据。(是不是感觉超级方便?妈妈再也不用担心我如何判断是否接收完1帧数据了。) 主函数 写的这个主函数,是用来验证接收的正确性的。RxCounter表示的是这一帧数据有几个字节,接收完一帧数据,会在中断函数里面把ReceiveState置1,然后,通过串口把接收到的数据发送回串口。这样,既验证了接收了多少字节的正确性,又验证了接收到的数据是否正确。 以上方法就可以利用接收不定长字节的数据,可以参考。

    时间:2021-02-27 关键词: 单片机 串口

  • 开源的Qt串口助手:一学就会

    串口调试助手是一款用于串口调试的工具,目前网上存在很多个版本,功能都差不多,但稳定性有好有坏,如果只用于一般的串口调试,这些工具够用了,如果想开发一款适于自己的串口调试助手,本文也许可以帮你。本文中的调试助手用QT开发,QT的开发环境不在这里详述了,不会安装的可以在网上找找类似的博文吧,以下仅供参考。 第一部分:代码托管: 此部分可能存在一些未知的bug,欢迎广大网友指出,为了方便管理和学习,所有代码均托管到gitee,链接地址:https://gitee.com/lumengcode/my-qt 第二部分效果展示: 实现的功能: 1.自动获取计算机的端口号;2.串口参数可更改:包括 波特率、数据位、停止位、校验和等............3.串口数据的发送和接收4.支持十六进制数据的发送和接收5.支持时间戳功能,方便文件的存储查看6.发送从窗口和接收窗口的清理7.定时发送功能............ 简单设置一下背景色,好看多了! 第二部分:代码部分: 1.当我们的计算机的端口号发生改变时,串口助手要具备实时扫面本机的端口号的功能,具有实时获取有效的串口信息,并将其刷新到下拉框中供我们选择。 有些自己编写的串口助手是没有这个功能的,这里我给大家补充上去。 //使用foreach获取有效的串口信息 foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { //这里相当于自动识别串口号之后添加到了cmb,如果要手动选择可以用下面列表的方式添加进去 Serial.setPort(info); if(Serial.open(QIODevice::ReadWrite)) { //将串口号添加到cmb ui->comboBox_Port->addItem(info.portName()); //关闭串口等待人为(打开串口按钮)打开 Serial.close(); } } 2.填充下拉框的波特率、数据位、停止位、效验位….,初始化下拉框默认参数,这个参数设置大部分的串口助手都会具备,因此不足为奇。 该有的功能个咱还是得有的。 // 填充波特率 QStringList Baud; Baud<<"1200"<<"2400"<<"4800"<<"9600"<<"38400"<<"115200"; ui->comboBox_Baud->addItems(Baud); // 填充数据位 QStringList DataBit; DataBit<<"5"<<"6"<<"7"<<"8"; ui->comboBox_DataBit->addItems(DataBit); // 填充停止位 QStringList StopBit; StopBit<<"1"<<"1.5"<<"2"; ui->comboBox_StopBit->addItems(StopBit); // 填充效验位 QStringList CheckBit; CheckBit<<"奇效验"<<"偶效验"<<"无"; ui->comboBox_CheckBit->addItems(CheckBit); //初始化默认参数 ui->comboBox_Baud->setCurrentIndex(3); //默认9600 ui->comboBox_DataBit->setCurrentIndex(3); //默认8bit Data ui->comboBox_StopBit->setCurrentIndex(0); //默认1bit Stop ui->comboBox_CheckBit->setCurrentIndex(2); //默认 无效验 3.串口打开和关闭按钮操作,这个就是打开串口按钮和关闭按钮的逻辑操作,成功打开串口后,相应的参数将会被设置。串口即可以用于数据的发送和接收了,这里也处理,打开失败时的逻辑操作,可谓是“疏而不漏也!”。 //串口打开和关闭按钮void MainWindow::on_pushButton_Open_clicked(){ //设置串口号;也就是说打开的是当前显示的串口 if(ui->comboBox_Port->currentText().isEmpty()) { QMessageBox::information(this,"提示","没有可用的串口"); return; } Serial.setPortName(ui->comboBox_Port->currentText()); if(ui->pushButton_Open->text() == "打开串口") { if(Serial.open(QIODevice::ReadWrite))//读写方式打开,成功后设置串口 { //设置波特率 Serial.setBaudRate(ui->comboBox_Baud->currentText().toInt()); //设置数据位 switch(ui->comboBox_DataBit->currentText().toInt()) { case 5: Serial.setDataBits(QSerialPort::Data5); break; case 6: Serial.setDataBits(QSerialPort::Data6); break; case 7: Serial.setDataBits(QSerialPort::Data7); break; case 8: Serial.setDataBits(QSerialPort::Data8); break; default: QMessageBox::information(this,"提示","数据位配置出错"); return; break; } //设置校验位 if (ui->comboBox_CheckBit->currentText() == "奇效验") { Serial.setParity(QSerialPort::OddParity); } else if (ui->comboBox_CheckBit->currentText() == "偶效验") { Serial.setParity(QSerialPort::EvenParity); } else if (ui->comboBox_CheckBit->currentText() == "无") { Serial.setParity(QSerialPort::NoParity); } //设置停止位 if (ui->comboBox_StopBit->currentText().toFloat() == 1) { Serial.setStopBits(QSerialPort::OneStop); } else if(ui->comboBox_StopBit->currentText().toFloat() == 1.5) { Serial.setStopBits(QSerialPort::OneAndHalfStop); } else if(ui->comboBox_StopBit->currentText().toFloat() == 2) { Serial.setStopBits(QSerialPort::TwoStop); } //设置流控制 Serial.setFlowControl(QSerialPort::NoFlowControl); ui->pushButton_Open->setText("关闭串口"); //建立串口接收的槽函数 connect(&Serial,&QSerialPort::readyRead ,this,&MainWindow::ReadRecData); // timer0->start(100); } else//串口打开失败 { QMessageBox::about(NULL, "提示", "打开出错,串口被占用!"); return ; } } else if(ui->pushButton_Open->text() == "关闭串口") { Serial.close();//关串口 //timer0->stop(); ui->pushButton_Open->setText("打开串口"); }} 4. 串口接收数据函数(支持时间戳、HEX接收) 这个是很关键的地方了,要保证数据接收的完整性和实时性,可采用两种接收数据的模式:定时器触发和槽触发,定时器触发我这里采用的是100ms的中断接收,大家还可以调的更小一点。 void MainWindow::ReadRecData(){ QByteArray readData = Serial.readAll();//读取串口数据 QByteArray NewData; QString current_date; if(readData != NULL)//将读到的数据显示到数据接收区 { if(HexRecvFlag) //判断是否使用HEX { //判断是否使用时间戳 if(EnableTimeFlag == 1) { current_date_time = QDateTime::currentDateTime(); current_date += "["; current_date += current_date_time.toString("yyyy-MM-dd hh:mm:ss"); current_date += "]收->"; ui->textEdit_Recv->append(current_date.toUtf8() + readData.toHex()); } else { ui->textEdit_Recv->append(readData.toHex()); } } else { //判断是否使用时间戳 if(EnableTimeFlag == 1) { current_date_time = QDateTime::currentDateTime(); current_date += "["; current_date += current_date_time.toString("yyyy-MM-dd hh:mm:ss"); current_date += "]收->"; ui->textEdit_Recv->append(current_date.toUtf8() + readData); } else { ui->textEdit_Recv->append(readData); } } }} 5. 串口发送数据函数(支持时间戳、HEX接收) 这个是很关键的地方了,串口发送数据的方式就比较简单了,直接将数据送入缓冲区 //发送数据void MainWindow::on_pushButton_Send_clicked(){ QString DataStr; QString NewData; QString current_date; DataStr = ui->textEdit_Send->toPlainText(); if(ui->pushButton_Open->text() == "打开串口") { QMessageBox::information(this,"提示","未打开串口"); return; } if(EnableTimeFlag == 1) { current_date_time = QDateTime::currentDateTime(); current_date += "["; current_date += current_date_time.toString("yyyy-MM-dd hh:mm:ss"); current_date += "]发->"; NewData = current_date + DataStr; } else { NewData = DataStr; } if(HexSendFlag) { Serial.write(DataStr.toUtf8().toHex());//写入缓冲区 } else { ui->textEdit_Recv->append(NewData.toUtf8()); } 6.清除接收和发送窗口数据函数,为了方便调试和观察,这里添加了清除接收和发送窗口数据函数的操作。 //清除接收窗口数据void MainWindow::on_pushButton_ClearRecv_clicked(){ ui->textEdit_Recv->clear();} //清除发送窗口数据void MainWindow::on_pushButton_2_clicked(){ ui->textEdit_Send->clear();} 7.使能时间戳,时间戳的主要目的在于通过一定的技术手段,对数据产生的时间进行认证,从而验证这段数据在产生后是否经过篡改。所以时间戳服务的提供者必须证明服务中使用的时间源是可信的,所提供的时间戳服务是安全的。 void MainWindow::on_checkBox_EnableTime_clicked(bool checked){ if(checked == true) { EnableTimeFlag = 1; } else { EnableTimeFlag = 0; }} 8. 使能定时发送,定时发送很香了,必须得有啊! void MainWindow::on_checkBox_clicked(bool checked){ if(checked == true) { if(ui->pushButton_Open->text() == "打开串口") { QMessageBox::information(this,"提示","未打开串口"); ui->checkBox->setChecked(false); return; } quint32 stime= ui->lineEdit_STime->text().toInt(); timer_id1 = startTimer(stime); ui->lineEdit_STime->setEnabled(false); } else { killTimer(timer_id1); ui->lineEdit_STime->setEnabled(true); }} 9. 使能HEX 发送和接收按钮,HEX那是标配,我只希望不要出bug,慢慢完善吧! void MainWindow::on_checkBox_HexRecv_clicked(bool checked){ if(checked) { HexRecvFlag = 1; } else HexRecvFlag = 0;} void MainWindow::on_checkBox_HexSend_clicked(bool checked){ if(checked) HexSendFlag = 1; else HexSendFlag = 0;} 10. 定时器中断函数 触发接收串口数据的核心,没它啥也干不了。 void MainWindow:: timerEvent(QTimerEvent *ev){ if(ev->timerId() == timer_id1) { on_pushButton_Send_clicked(); }} 串口助手部分最后的展示效果

    时间:2021-01-29 关键词: 串口调试 Qt串口 串口

  • 使用J-Link也能实现串口打印输出数据的功能

    作者 | strongerHuang 微信公众号 | 嵌入式专栏 嵌入式软件基本都会存在打印输出数据的情况,我们最常见就是串口打印输出。 如果我们手里没有232转USB,或者TTL转USB工具,此时,使用J-Link工具同样也可以实现串口打印输出数据的功能。 下面就来讲讲使用J-link的『RTT Viewer』功能实现打印输出的方法: 1概述 SWO:Serial Wire Output,串行线输出 RTT:Real Time Transfer,实时传输 前面SWO文章,实现原理是通过MCU的SWO引脚输出信息(到显示终端SWV)。 而本文讲述的RTT不需要通过额外SWO引脚,即可实现printf输出,而且性能(耗时)远高于SWO。 2关于RTT SEGGER实时传输(RTT)是一种在嵌入式应用中实现交互式用户I/O的技术。 它结合了SWO和半主机( semihosting)的优点,具有很高的性能。 使用RTT,可以从目标微控制器输出信息,并以非常高的速度向应用程序发送输入,而不会影响目标的实时性。 Cortex - M0不支持SWO,而本文讲述的RTT则支持Cortex - M0,文末提供STM32F0工程。 3关于J-Link RTT Viewer J-Link RTT Viewer是在调试主机上使用RTT功能的Windows GUI应用程序。 RTT Viewer可以独立使用,打开自己与J-Link的连接,并与正在运行的调试会话目标或并行,连接到它并使用现有的J-Link连接。 RTT Viewer支持RTT的主要功能: ·通道0上的终端输出 ·将文本输入发送到通道0 ·最多16个虚拟终端,只有一个目标通道 ·控制文本输出:彩色文本,擦除控制台 ·在通道1上记录数据 本文主要结合J-Link RTT Viewer讲述,当然支持RTT的还有J-Link RTT Client 和J-Link RTT Logger。 更多相关介绍,可以参看: https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer 4获取RTT源码 我们需要在工程中添加RTT源码,同时需要J-Link RTT Viewer查看器支持。 J-Link / J-Trace下载地址(Windows版本): https://www.segger.com/downloads/jlink/JLink_Windows.exe 安装之后,在安装目录下包含RTT源码: C:\Program Files (x86)\SEGGER\JLink\Samples\RTT 解压SEGGER_RTT_V***.zip之后,复制整个RTT目录源码到你工程。 提示: 解压之后,只需复制RTT目录就行。 4.1 添加RTT到工程 添加源码文件到工程主要有两个步骤:1.添加源码文件到工程。2.添加文件路径。 当然,我下面有提供添加好的源码工程。 4.2 应用程序 调用RTT的打印,和常规的printf类似。 添加头文件:#include "SEGGER_RTT.h" 再调用SEGGER_RTT_printf函数打印输出: 这里SEGGER_RTT_printf和print不同的是:前面多了一个“终端号”参数。(我们使用终端0) 5RTT Viewer配置、输出 和前面讲述的SWV查看器类似,配置相关信息即可输出。 安装目录:C:\Program Files (x86)\SEGGER\JLink 下载程序到MCU,连接J-Link,打开安装目录下的J-Link RTT Viewer,配置参数: 输出效果: 6下载 为方便大家理解,提供源码工程下载,参考代码: STM32F051(HAL)_JLink-RTT STM32F103(HAL)_JLink-RTT 百度网盘: https://pan.baidu.com/s/1aYBuHtOgtLqLvj6SsMYlQA 提取码:nbd3 提示: 1.公众号不支持外链接,请复制链接到浏览器打开。 2.源码仅供个人学习参考,不一定适用于实际项目。 3.若链接失效,请关注公众号,回复『printf系列教程』获取最新链接。 7 说明 1.该文档仅供个人学习使用,版权所有,禁止商用。 2.本文由我一个人编辑并整理,难免存在一些错误。

    时间:2021-01-27 关键词: 输出 J-Link 串口

  • STM32串口发送数据和接收数据方式总结

    串口发送数据 1、串口发送数据最直接的方式就是标准调用库函数 。 void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展: void Send_data(u8 *s){ while(*s!='\0') {   while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);   USART_SendData(USART1,*s);  s++; }} 以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。 while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET); 这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下: void Send_data(USART_TypeDef * USARTx,u8 *s){ while(*s!='\0') {   while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET);   USART_SendData(USARTx,*s);  s++; }} 这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。 当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下: void USART_printf ( USART_TypeDef * USARTx, char * Data, ... ){ const char *s; int d;    char buf[16];  va_list ap; va_start(ap, Data);  while ( * Data != 0 )     // 判断是否到达字符串结束符 {                                if ( * Data == 0x5c )  //'\'  {              switch ( *++Data )   {    case 'r':                 //回车符    USART_SendData(USARTx, 0x0d);    Data ++;    break;     case 'n':                 //换行符    USART_SendData(USARTx, 0x0a);     Data ++;    break;     default:    Data ++;    break;   }      }    else if ( * Data == '%')  {           //   switch ( *++Data )   {        case 's':            //字符串    s = va_arg(ap, const char *);        for ( ; *s; s++)     {     USART_SendData(USARTx,*s);     while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );    }        Data++;        break;     case 'd':        //十进制    d = va_arg(ap, int);        itoa(d, buf, 10);        for (s = buf; *s; s++)     {     USART_SendData(USARTx,*s);     while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );    }        Data++;        break;        default:    Data++;        break;       }     }    else USART_SendData(USARTx, *Data++);    while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );   }} 该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。 2、 直接使用printf函数。 很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数: 如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用: 相关笔记:串口打印知多少? 串口接收数据 串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。 这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。 #define Max_BUFF_Len 18unsigned char Uart2_Buffer[Max_BUFF_Len];unsigned int Uart2_Rx=0;void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生  {  USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志      Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);     //接收串口1数据到buff缓冲区  Uart2_Rx++;           if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len)    //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收)  {   if(Uart2_Buffer[0] == '+')                      //检测到头标识是我们需要的    {    printf("%s\r\n",Uart2_Buffer);        //这里我做打印数据处理    Uart2_Rx=0;                                      }    else   {    Uart2_Rx=0;                                   //不是我们需要的数据或者达到最大接收数则开始重新接收   }  } }} 数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。 这样做的有以下好处: 可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改 可以接受指定的数据 防止接收的数据使数组越界 这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。 以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。 所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。 #define DMA_USART1_RECEIVE_LEN 18void USART1_IRQHandler(void)                                 {         u32 temp = 0;      uint16_t i = 0;            if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)      {          USART1->SR;          USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志            DMA_Cmd(DMA1_Channel5,DISABLE);          temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小         for (i = 0;i 

    时间:2020-12-28 关键词: 单片机 串口

  • FPGA 电源部分电路原理,你值得收藏!

    FPGA 电源部分电路原理,你值得收藏!

    U22 是电可擦除 ROM,用于存放 AS 下载后的数据,使得 FPGA 的程序段掉电也能得以保存,DATA 端是数据读取端,用于读取 ROM 内数据。DCLK 为时钟端口,用于接收时钟信号进行同步传输。nCS 是片选端口,用于接收片选信号表示对该芯片进行通讯。ASDI 为 AS 下载数据输入端,用于接收 AS 下载数据。VCC 与 GND 分别为电源端口与地端口,分别接 3.3V 与数字地。 FPGA 电源设计部分电路原理图如图 5-1 所示: Header 18X2 为 18 排 2 列排阵,两组排阵分别与 PIN 口、3.3V 电源、数字地相连,提供了可动的机制,使得 PIN 口可根据需要用排线与目标相连,打到信号传输的目的。而 3.3V 电源以及数字地针口则可以根据需要,用排线为目标提供逻辑高电平或逻辑低电平。 U21D 为 FPGA 芯片的时钟信号接收部分,通过网络标号“CLK0~3”与对应的时钟信号端口相连。 U21C 为 FPGA 芯片的供电及接地部分,含有“GND”字样的是“地”端口,与数字地相连,VCCIO1~4 为 I/O 口供电端口,采用 3.3V 电源供电,通过网络标号“+3.3V”与 3.3V 电源端口相连。VCCA_PLL1、VCCA_PLL2、VCCINT 为内部运算器和输入缓冲区的供电端口,采用 1.5V 电源供电,通过网络标号“+1.5V”与 1.5V 电源端口相连。 U21B 为 JTAG 与 AS 下载部分,TMS、TCK、TD1、TD0 分别为 JATAG 下载方式的模式选择端、时钟信号端、数据输入端、数据输出端。DATA0 为 AS 下载的数据端口,MSEL0、MSEL1、nCE、nCEO、CONF_ DONE、nCONFIG、nSTATUS 端口按照典型接法相连。值得注意的是:无论 AS 还是 JTAG 都是通过 JTAG 标准通讯,AS 下载一般是下载 POF 到 PROM(flash)里,重新上电仍然可以加载,JTAG 下载是通过 JTAG 口将 sof 文件直接下载到 FPGA 内,一般是临时调试用的,掉电就丢失了。

    时间:2020-10-20 关键词: FPGA 电源 串口

  • LPC2364的串口转网口专用协议卡的研制方案

    LPC2364的串口转网口专用协议卡的研制方案

    LPC2364的串口转网口专用协议卡的研制方案 摘要:给出了采用LPC2364芯片为处理器,并利用以太网中TCP协议来设计串口转网口模块,从而实现数据传输方式转换的一种设计方法。该方法中的软件采用FreerRtos实时多任务嵌入式系统和uIP协议栈来实现串口数据通讯和网口数据通讯两项任务。文中同时给出了系统框图和主程序流程图。关键词:TCP/IP协议;LPC2364;uIP;FreeRTOS;串口转网口 O 引言    串口转网口模块是一个可以让串口设备立即具备联网能力的设备联网服务器。它具有1个可选择界面串口和1个TCP/IP网络接口,可让串口设备立即连接网络。从而实现工业设备完全自动化联网管理。该模块体积小,非常容易整合在系统或设备内,而且可以适应复杂的网络。为此,本文给出了采用LPC2364、DP83848C、SP3485和H2019等芯片构成一个串口转网口模块的软硬件实现方法。 1 uIP介绍    uIP是由瑞典计算机科学学院(网络嵌入式系统小组)的Adam Dunkels开发的一种软件协议栈。该协议栈的源代码由C语言编写,并完全公开。uIP协议栈去掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保留了网络通信必须使用的协议。它把设计重点放在了IP/TCP /ICMP/UDP/ARP这些网络层和传输层协议上,故可保证其代码的通用性和结构的稳定性。    由于uIP协议栈是专门为嵌入式系统而设计的。因此,uIP还具有如下优越功能:    ◇代码非常少,其协议栈代码不到6K,很方便阅读和移植。    ◇占用的内存数非常少,RAM占用仅几百字节。    ◇其硬件处理层、协议栈层和应用层共用一个全局缓存区,且不存在数据的拷贝,发送和接收都是依靠这个缓存区,故可极大地节省空间和时间。    ◇支持多个主动连接和被动连接并发。    ◇源代码中提供的实例程序包括web服务器、web客户端、电子邮件发送程序(SMTP客户端)、Telnet服务器、DNS主机名解析程序等。而且通用性强,移植后基本不用修改就可以通过。    ◇对数据的处理采用轮循机制,不需要操作系统的支持。    由于uIP对资源的需求较少且移植很容易,因此,大部分具有小RAM的微控制器都可以使用uIP协议栈。 2 FreeRTOS介绍    FreeRTOS是一款可移植且源代码开放的微型实时内核。可为多种不同的处理器架构和开发工具提供移植包。每个官方移植包都包含一个配置好的应用范例,可用来展示内核特性,加快学习进程。    FreeRTOS是一种专为小型嵌入式系统设计的,可扩展的实时内核。其亮点在于其设计遵循小型、简单、易用的原则,同时可支持任务(tasks)和协程(co-rouTInes)以及队列、二进制信号量、计数信号量、递归信号量和互斥量等,可用于任务之间、任务和中断之间的通信和同步。 3 串口转网口模块的硬件实现    串口转网口模块使用到的芯片有LPC2364、DP83848C、SP3485和H2019,其系统的硬件电路图如图1所示。 4 串口转网口模块的软件实现    本串口转网口模块的软件需要建立两个任务,一是初始化,二是任务调度。其中初始化包括时钟初始化,协议栈初始化,IP地址初始化,网关地址初始化,子网掩码初始化,网口初始化。串口初始化等。其主函数代码如下:        图2所示是其主函数流程图。主函数中可进行uIP协议栈初始化和串口初始化的并使并设置,同时通过操作系统初始化来建立两个通讯任务,然后就可以开始操作系统的任务调度。图3所示是系统中的串口任务控制流程。                 5 协议转换卡的通讯试验    本文的协议转换卡并不是通用意义上的协议转换卡,而是基于特定串口通讯协议的转换卡。该卡在规定的协议中,由网口接收到的数据可以分为两种,一种是控制命令,一种是查询命令。在软件中,串口任务和网口任务有两个共享的数据缓冲区,通过串口任务可检查缓冲区,如果缓冲区中有数据,则根据通讯协议判断这些数据是否是正确的指令,若是正确的指令,则判断是查询命令还是控制命令,若是控制命令,则将此控制命令发送出去,并清空缓冲区;若是查询命令,网口任务则会到另一个缓冲区中取出数据,并用协议栈将此数据发送出去,同时清空缓冲区。通过用TCP通讯客户端检测工具和串口调试助手调试可以发现,如果TCP通讯客户端发出的是查询命令,则网口任务自动到预定的缓冲区取出数据,并发送出来,同时在TCP通讯客户端上显示出来;如果TCP通讯客户端发出的是控制命令,则等待串口调试助手的返回数据。如果有返回,则在TCP通讯客户端上显示出来;如果串口助手没有返回,软件控制则一直发送控制命令,直到收到正确的回复。 6 结束语    本文所设计串口转网口的转换卡是具有串口通讯协议的转换卡。协议卡对收到的数据会进行分析和判断,进而决定数据的发送方式,从而实现FreeRTOS操作系统和uIP协议栈的结合。此外,由于FreeRTOS操作系统和uIP协议栈对用户而言是透明的,因此,该模块可以方便地随时修改串口通讯速率、串口通讯格式、IP地址、网关、子网掩码等功能.并充分利用FreeRTOS操作系统的稳定性与可靠性以及实时性好等特点,同时可发挥以太网通讯效率高的特点,来为实施数据转换提供方便。

    时间:2020-09-10 关键词: lpc2364 串口

  • uart串口通信c语言实现

    uart串口通信c语言实现

      通信,按照传统的理解就是信息的传输与交换。对于单片机来说,通信则与传感器、存储芯片、外围控制芯片等技术紧密结合,成为整个单片机系统的“神经中枢”。没有通信,单片机所实现的功能仅仅局限于单片机本身,就无法通过其它设备获得有用信息,也无法将自己产生的信息告诉其它设备。如果单片机通信没处理好的话,它和外围器件的合作程度就受到限制,最终整个系统也无法完成强大的功能,由此可见单片机通信技术的重要性。UART(Universal Asynchronous Receiver/Transmitter,即通用异步收发器)串行通信是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。   1. 串口的基本概念   1.1 UART - 串行异步收发器 Universal Asynchronous Receiver/Transmitter   串行/并行(课后补充)   异步/同步:‘异步/同步通信两者之间的区别’ (补充)   ‘单工/半双工/全双工:   单工:任何时候数据只能朝一个方向传输   半双工:数据可以向两个方向传输,任何同一时刻只能朝同一方向传输   全双工:数据可以同时向两个方向传输   1.2 串口通信标准   RS232 (电子工业协议EIA) - 目前最常用的’串行接口标准‘   规定了’电气特性‘:   逻辑 0 ,+3 v ~ +15 v,SPACE   逻辑 1 ,- 3 v ~ - 15 v,MARK   规定了’机械特性‘:   传输距离 《 10 m   TTL电平,计算机内部电平(CPU):   逻辑 0 ,低电平 《 0.8 v   逻辑 1 ,高电平 》 2.4 v   串行异步通信的重要参数:   》》数据位个数: 5 ~ 8 bit (开发板那端定好的是 8 bit / 帧数据)   》》验证方式:奇校验、偶校验、无校验   》》停止位宽度:1~2bit   》》通信的速率:bps (bit per second - 每秒传输bit位)’波特率单位‘   完成串口通信有两种方式:   1) 一种方式:运行在arm core的程序和LED一样直接操作GPIO管脚,形成串行异步收发数据的时序。   2) 另一方式:S5P6818中集成了uart控制器,方式 1)纯软件实现通信的过程就可以使用软硬件结合的方式来实现通信时序,从而简化软件编程。      UART串口程序   一般情况下,我们编写串口通信程序的基本步骤如下所示:   1、配置串口为模式1。   2、配置定时器T1为模式2,即自动重装模式。   3、根据波特率计算TH1和TL1的初值,如果有需要可以使用PCON进行波特率加倍。   4、打开定时器控制寄存器TR1,让定时器跑起来。   这里还要特别注意一下,就是在使用T1做波特率发生器的时候,千万不要再使能T1的中断了。   我们先来看一下由IO口模拟串口通信直接改为使用硬件UART模块时的程序代码,看看程序是不是简单了很多,因为大部分的工作硬件模块都替我们做了。程序功能和IO口模拟的是完全一样的。   #include 《reg52.h》   void ConfigUART(unsigned int baud);   void main()   {   ConfigUART(9600); //配置波特率为9600   while (1)   {   while (!RI); //等待接收完成   RI = 0; //清零接收中断标志位   SBUF = SBUF + 1; //接收到的数据+1后,发送回去   while (!TI); //等待发送完成   TI = 0; //清零发送中断标志位   }   }   /* 串口配置函数,baud-通信波特率 */   void ConfigUART(unsigned int baud)   {   SCON = 0x50; //配置串口为模式1   TMOD &= 0x0F; //清零T1的控制位   TMOD |= 0x20; //配置T1为模式2   TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值   TL1 = TH1; //初值等于重载值   ET1 = 0; //禁止T1中断   TR1 = 1; //启动T1   }   当然了,这个程序还是用在主循环里等待接收中断标志位和发送中断标志位的方法来编写的,而实际工程开发中,当然就不能这么干了,我们也只是为了用直观的对比来告诉同学们硬件模块可以大大简化程序代码,那么实际使用串口的时候就用到串口中断了,来看一下用中断实现的程序。请注意一点,因为接收和发送触发的是同一个串口中断,所以在串口中断函数中就必须先判断是哪种中断,然后再作出相应的处理。   #include 《reg52.h》   void ConfigUART(unsigned int baud);   void main()   {   EA = 1; //使能总中断   ConfigUART(9600); //配置波特率为9600   while (1);   }   /* 串口配置函数,baud-通信波特率 */   void ConfigUART(unsigned int baud)   {   SCON = 0x50; //配置串口为模式1   TMOD &= 0x0F; //清零T1的控制位   TMOD |= 0x20; //配置T1为模式2   TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值   TL1 = TH1; //初值等于重载值   ET1 = 0; //禁止T1中断   ES = 1; //使能串口中断   TR1 = 1; //启动T1   }   /* UART中断服务函数 */   void InterruptUART() interrupt 4   {   if (RI) //接收到字节   {   RI = 0; //手动清零接收中断标志位   SBUF = SBUF + 1; //接收的数据+1后发回,左边是发送SBUF,右边是接收SBUF   }   if (TI) //字节发送完毕   {   TI = 0; //手动清零发送中断标志位   }   }   大家可以试验一下,看看是不是和前边用IO口模拟通信实现的效果一致,而主循环却完全空出来了,我们就可以随意添加其它功能代码进去。

    时间:2020-08-06 关键词: uart C语言 串口

  • RS232串口通讯协议解析

    RS232串口通讯协议解析

      串行通信接口标准经过使用和发展,目前已经有几种。但都是在RS-232标准的基础上经过改进而形成的。所以,以RS-232C为主来讨论。   在讨论RS-232C接口标准的内容之前,先说明两点。首先,RS-232-C标准最初是远程通信连接数据终端设备DTE(Data Terminal Equipment)与数据通信设备DCE(Data CommunicaTIon Equipment)而制定的。因此这个标准的制定,并未考虑计算机系统的应用要求。但目前它又广泛地被借来用于计算机(更准确的说,是计算机接口)与终 端或外设之间的近端连接标准。显然,这个标准的有些规定及和计算机系统是不一致的,甚至是相矛盾的。有了对这种背景的了解,我们对RS-232C标准与计 算机不兼容的地方就不难理解了   其次,RS-232C标准中所提到的“发送”和“接收”,都是站在DTE立场上,而不是站在DCE的立场来定义的。由于在计算机系统中,往往是CPU和I/O设备之间传送信息,两者都是DTE,因此双方都能发送和接收。   RS- 323C标准是美国EIA(电子工业联合会)与BELL等公司一起开发的1969年公布的通信协议。它适合于数据传输速率在0~20000b/s范围内的 通信。这个标准对串行通信接口的有关问题,如信号线功能、电器特性都作了明确规定。由于通行设备厂商都生产与RS-232C制式兼容的通信设备,因此,它 作为一种标准,目前已在微机通信接口中广泛采用。   一、RS-232-C   RS-232C标准(协议)的全称是EIA-RS-232C标准,其中EIA(Electronic Industry AssociaTIon)代表美国电子工业协会,RS(ecommeded standard)代表推荐标准,232是标识号,C代表RS232的最新一次修改(1969),在这之前,有RS232B、RS232A。。它规定连接 电缆和机械、电气特性、信号功能及传送过程。常用物理标准还有有EIA?RS-232-C、EIA?RS-422-A、 EIA?RS-423A、EIA?RS-485。这里只介绍EIA?RS-232-C(简称232,RS232)。 例如,目前在IBM PC机上的COM1、COM2接口,就是RS-232C接口。   1.电气特性   EIA-RS-232C对电器特性、逻辑电平和各种信号线功能都作了规定。   在TxD和RxD上:逻辑1(MARK)=-3V~-15V   逻辑0(SPACE)=+3~+15V   在RTS、CTS、DSR、DTR和DCD等控制线上:   信号有效(接通,ON状态,正电压)=+3V~+15V   信号无效(断开,OFF状态,负电压)=-3V~-15V      图1   以上规定说明了RS-323C标准对逻辑电平的定义。对于数据(信息码):逻辑“1”(传号)的电平低于-3V,逻辑“0”(空号)的电平告 语+3V;对于控制信号;接通状态(ON)即信号有效的电平高于+3V,断开状态(OFF)即信号无效的电平低于-3V,也就是当传输电平的绝对值大于 3V时,电路可以有效地检查出来,介于-3~+3V之间的电压无意义,低于-15V或高于+15V的电压也认为无意义,因此,实际工作时,应保证电平在± (3~15) V之间。   EIA-RS-232C与TTL转换:EIA-RS-232C是用正负电压来表示逻辑状态,与TTL以高低电平表示逻辑状态的规定不同。因此,为了能 够同计算机接口或终端的TTL器件连接,必须在EIA-RS-232C与TTL电路之间进行电平和逻辑关系的变换。实现这种变换的方法可用分立元件,也可 用集成电路芯片。目前较为广泛地使用集成电路转换器件,如MC1488、SN75150芯片可完成TTL电平到EIA电平的转换,而MC1489、 SN75154可实现EIA电平到TTL电平的转换。MAX232芯片可完成TTL←→EIA双向电平转换,图1显示了1488和1489的内部结构和引 脚。MC1488的引脚(2)、(4,5)、(9,10)和(12,13)接TTL输入。引脚3、6、8、11输出端接EIA-RS-232C。 MC1498的14的1、4、10、13脚接EIA输入,而3、6、8、11脚接TTL输出。具体连接方法如图2所示。图中的左边是微机串行接口电路中的 主芯片UART,它是TTL器件,右边是EIA-RS-232C连接器,要求EIA高电压。因此,RS-232C所有的输出、输入信号都要分别经过 MC1488和MC1498转换器,进行电平转换后才能送到连接器上去或从连接器上送进来。      图2   2、连接器的机械特性   连接器:由于RS-232C并未定义连接器的物理特性,因此,出现了DB-25、DB-15和DB-9各种类型的连接器,其引脚的定义也各不相同。下面分别介绍两种连接器。   (1)DB-25:   PC和XT机采用DB-25型连接器。DB-25连接器定义了25根信号线,分为4组:   ①异步通信的9个电压信号(含信号地SG)2,3,4,5,6,7,8,20,22   ②20mA电流环信号 9个(12,13,14,15,16,17,19,23,24)   ③空6个(9,10,11,18,21,25)   ④保护地(PE)1个,作为设备接地端(1脚)   DB-25型连接器的外形及信号线分配如图3所示。注意,20mA电流环信号仅IBM PC和IBM PC/XT机提供,至AT机及以后,已不支持。      图3   (2)DB-9连接器   在AT机及以后,不支持20mA电流环接口,使用DB-9连接器,作为提供多功能I/O卡或主板上COM1和COM2两个串行接口的连接器。它只提供 异步通信的9个信号。DB-25型连接器的引脚分配与DB-25型引脚信号完全不同。因此,若与配接DB-25型连接器的DCE设备连接,必须使用专门的 电缆线。   电缆长度:在通信速率低于20kb/s时,RS-232C所直接连接的最大物理距离为15m(50英尺)。   最大直接传输距离说明:RS-232C标准规定,若不使用MODEM,在码元畸变小于4%的情况下,DTE和DCE之间最大传输距离为15m(50英 尺)。可见这个最大的距离是在码元畸变小于4%的前提下给出的。为了保证码元畸变小于4%的要求,接口标准在电气特性中规定,驱动器的负载电容应小于 2500pF。   3、RS-232C的接口信号   RS-232C规标准接口有25条线,4条数据线、11条控制线、3条定时线、7条备用和未定义线,常用的只有9根,它们是   (1)联络控制信号线:   数据装置准备好(Data set ready-DSR)——有效时(ON)状态,表明MODEM处于可以使用的状态。   数据终端准备好(Data set ready-DTR)——有效时(ON)状态,表明数据终端可以使用。   这两个信号有时连到电源上,一上电就立即有效。这两个设备状态信号有效,只表示设备本身可用,并不说明通信链路可以开始进行通信了,能否开始进行通信要由下面的控制信号决定。   请求发送(Request to send-RTS)——用来表示DTE请求DCE发送数据,即当终端要发送数据时,使该信号有效(ON状态),向MODEM请求发送。它用来控制MODEM是否要进入发送状态。   允许发送(Clear to send-CTS)——用来表示DCE准备好接收DTE发来的数据,是对请求发送信号RTS的响应信号。当MODEM已准备好接收终端传来的数据,并向前发送时,使该信号有效,通知终端开始沿发送数据线TxD发送数据。   这对RTS/CTS请求应答联络信号是用于半双工MODEM系统中发送方式和接收方式之间的切换。在全双工系统中作发送方式和接收方式之间的切换。在全双工系统中,因配置双向通道,故不需要RTS/CTS联络信号,使其变高。   接收线信号检出(Received Line detecTIon-RLSD)——用来表示DCE已接通通信链路,告知DTE准备接收数据。当本地的MODEM收到由通信链路另一端(远地)的 MODEM送来的载波信号时,使RLSD信号有效,通知终端准备接收,并且由MODEM将接收下来的载波信号解调成数字两数据后,沿接收数据线RxD送到 终端。此线也叫做数据载波检出(Data Carrier dectecTIon-DCD)线。   振铃指示(Ringing-RI)——当MODEM收到交换台送来的振铃呼叫信号时,使该信号有效(ON状态),通知终端,已被呼叫。   (2)数据发送与接收线:   发送数据(Transmitted data-TxD)——通过TxD终端将串行数据发送到MODEM,(DTE→DCE)。   接收数据(Received data-RxD)——通过RxD线终端接收从MODEM发来的串行数据,(DCE→DTE)。   (3)地线   有两根线SG、PG——信号地和保护地信号线,无方向。   上述控制信号线何时有效,何时无效的顺序表示了接口信号的传送过程。例如,只有当DSR和DTR都处于有效(ON)状态时,才能在DTE和DCE之间 进行传送操作。若DTE要发送数据,则预先将DTR线置成有效(ON)状态,等CTS线上收到有效(ON)状态的回答后,才能在TxD线上发送串行数据。 这种顺序的规定对半双工的通信线路特别有用,因为半双工的通信才能确定DCE已由接收方向改为发送方向,这时线路才能开始发送。   2个数据信号:发送TXD;接收RXD。   1个信号地线:SG。   6个控制信号:   DSR 数传机(即modem)准备好,Data Set Ready。   DTR 数据终端(DTE,即微机接口电路,如Intel8250/8251,16550)准备好,Data Terminal Ready。   RTS DTE请求DCE发送(Request To Send)。   CTS DCE允许DTE发送(Clear To Send),该信号是对RTS信号的回答。   DCD 数据载波检出,Data Carrier Detection当本地DCE设备(Modem)收到对方的DCE设备送来的载波信号时,使DCD有效,通知DTE准备接收, 并且由DCE将接收到的载波信号解调为数字信号, 经RXD线送给DTE。   RI 振铃信号 Ringing当DCE收到交换机送来的振铃呼叫信号时,使该信号有效,通知DTE已被呼叫。      二、远距离通信   第1和第2中情况是属于远距离通信(传输距离大于15m的通信)的例子,故一般要加调制解调器MODEM,因此使用的信号线较多。注意:在以下各图中,DTE信号为RS-232-C信号,DTE与计算机间的电平转换电路未画出。   1、采用Modem(DCE)和电话网通信时的信号连接   若在双方MODEM之间采用普通电话交换线进行通信,除了需要2~8号信号线外还要增加RI(22号)和DTR(20号)两个信号线进行联络,如图1所示。      图1   DSR、DTR:数传机(DCE)准备好、数据终端(DTE)准备好,只表示设备本身可用。   首先,通过电话机拔号呼叫对方,电话交换台向对方发出拔号呼叫信号,当对方DCE收到该信号后,使RI(振铃信号)有效,通知DTE,已被呼叫。当对方“摘机”后,两方建立了通信链路。   若计算机要发送数据至对方,首先通过接口电路(DTE)发出RTS(请求发送)信号。此时,若DCE(Modem)允许传送,则向DTE回答CTS (允许发送)信号。一般可直接将RTS/CTS接高电平,即只要通信链路已建立,就可传送信号。(RTS/CTS可只用于半双工系统中作发送方式和接收方 式的切换。   当DTE获得CTS信号后,通过TXD线向DCE发出串行信号,DCE(Modem)将这些数字信号调制成模拟信号(又称载波信号),传向对方。   计算机向DTE“数据输出寄存器”传送新的数据前,应检查Modem状态和数据输出寄存器为空。当对方的DCE收到载波信号后,向对方的DTE发出 DCD信号(数据载波检出),通知其DTE准备接收,同时,将载波信号解调为数据信号,从RXD线上送给DTE,DTE通过串行接收移位寄存器对接收到的 位流进行移位,当收到1个字符的全部位流后,把该字符的数据位送到数据输入寄存器,CPU可以从数据输入寄存器读取字符。   2、采用专用电话线通信   在通信双方的MODEM之间采用电话线进行通信,则只要使用2~8号信号线进行联络与控制。不需要电话机、振铃信号RI和DTR信号,其信号线的连接如图2那样。      图2   三、近距离通信   当通信距离较近时,可不需要Modem,通信双方可以直接连接,这种情况下,只需使用少数几根信号线。最简单的情况,在通信中根本不需要RS-232C的控制联络信号,只需三根线(发送线、接收线、信号地线)便可实现全双工异步串行通信,即是这里要讨论的第一种情况。   无Modem时,最大通信距离按如下方式计算:   RS-232C标准规定:当误码率小于4%时,要求导线的电容值应小于2500PF。对于普通导线,其电容值约为170PF/M。则允许距离L=2500PF/(170PF/M)=15M   这一距离的计算,是偏于保守的,实际应用中,当使用9600bps,普通双绞屏蔽线时,距离可达30~35米。   1、零Modem 的最简连线(3线制)   图3是零MODEM方式的最简单连接(即三线连接),图中的2号线与3号线交叉连接是因为在直连方式时,把通信双方都当作数据终端设备看待,双方都可发也可收。在这种方式下,通信双方的任何一方,只要请求发送RTS有效和数据终端准备好DTR有效就能开始发送和接收。      图3   (1)RTS与CTS互联:只要请求发送,立即得到允许   (2)DTR与DSR互联:只要本端准备好,认为本端立即可以接收(DSR、数传机准备好)。   2、零Modem标准连接   如果想在直接连接时,而又考虑到RS-232C的联络控制信号,则采用零MODEM方式的标准连接方法,其通信双方信号线安排如下1-2-3-4-5顺序所演示的那样。   无Modem的标准联线(7线制)如图所示:   从中可以看出,RS-232C接口标准定义的所有信号线都用到了,并且是按照DTE和DCE之间信息交换协议的要求进行连接的,只不过是把DTE自己发出的信号线送过来,当作对方DCE发来的信号,因此,又把这种连接称为双叉环回接口。   双方的握手信号关系如下(注:甲方乙方并未在图中标出):   (1)当甲方的DTE准备好,发出DTR信号,该信号直接联至乙方的RI(振铃信号)和DSR(数传机准备好)。即只要甲方准备好,乙方立即产生呼叫(RI)有效,并同时准备好(DSR)。尽管此时乙方并不存在DCE(数传机)。   (2)甲方的RTS和CTS相连,并与乙方的DCD互连。即:一旦甲方请求发送(RTS),便立即得到允许(CTS),同时,使乙方的DCD有效,即检测到载波信号。   (3)甲方的TXD与乙方的RXD相连,一发一收。              

    时间:2020-08-06 关键词: rs232 通讯协议 串口

  • 串口调试要注意什么?串口调试工具有哪些?

    串口调试要注意什么?串口调试工具有哪些?

    1. 何谓串口? 串口几乎为所有计算机的装置通讯协议标准。请别与通用串行总线 (Universal serial bus,USB) 产生混肴。大多数的计算机均配备 2 组 EIA-232 架构的串行端口。串口亦为常见的通讯协议,适用于控制多种仪器设备,并可搭配 EIA-232 通讯端口使用多款 GPIB 兼容的装置。此外,用户可透过数据撷取的串口通讯功能,进而整合远程取样装置。请注意,EIA-232 与 EIA-485/422 亦可为所谓的 RS-232 与 RS-485/422。 串口通讯的概念极为简单。串行端口将同时传送并接收 1 个位 (Bit) 的信息字节 (Byte)。虽然此传输量低于并行通讯作业,却可传输完整的字节;适用于较长距离的通讯作业。以 IEEE 488 规格的平行通讯作业为例,设备之间的接线总长度不得超过 20米(65英尺);任两组装置之间的长度不超过 2米(6.5英尺)。而串口却可达最长 1200米(4000英尺)。   一般情况下,工程师均使用串行传输 ASCII 数据。并透过三种传输线完成通讯作业 - 接地线 (Ground)、传送线 (Transmit)与接收线 (Receive)。由于串口属于异步化,因此串行端口可于其中 1 个信道传送数据,并于另 1 个信道接收数据。其他通道可视情况而进行握手(Handshaking)。重要的串口特性为波特率 (Baud rate)、数据位、停止位 (Stop bit),与奇偶同位 (Parity)。若要沟通两组通讯端口,则必须符合这些参数: 1、波特率 (Baud rate) 为通讯的速度量测作业,显示每秒所传输的位数。举例来说,300 波特率即为每秒达 300个位。工程师所称的频率周期 (Clock cycle) 即为波特率;若协议呼叫信号 (Protocol call) 为 4800 波特率,意即频率为 4800 Hz。亦表示串行端口以 4800 Hz 的速率,进行数据信道的取样。常见的电话线路波特率为 14400、28800,与 33600。波特率当然可以大于上述这些数字,但这些速率将限制设备之间的距离。因此高波特率均用于装置距离相近的通讯作业,常见的即为 GPIB 装置。 2、数据位数 (Data bit),代表传输作业中的实际数据位。当计算机传送信息框架 (Frame) 时,实际数据总数可能不满 8 位。框架的标准数值为 5、7,与 8 位。应根据所传输的信息,选择所需的设定。举例来说,标准 ASCII 可为 0 ~ 127 的数值 (7 位)。延伸的 ASCII 则使用 0 ~ 255 (8 位)。若传输中的数据为标准 ASCII,则各个框架若能传送 7 位数据,即属高效率的通讯作业。1 个框架即为单一字节 (Byte) 的传输,包含开始/停止 (Start/stop) 位、数据位,与奇偶校验 (Parity)。由于所选的通讯协议将影响实际位数,因此可使用“框架 (Frame)”代表所有的范例。 停止位 (Stop bit) 可针对单一框架的通讯作业末端发出信号。常见数值为 1、1.5,与 2 位。由于数据将受到跨信道的频率所影响,而各组装置又具有自己的频率,因此任 2 组装置可能会稍稍落后同步化作业。因此,停止位不仅可指出传输作业末端,并可为计算机频率速度提供发生错误的空间。停止位所占的位数越多,则不同频率的同步化越具弹性;但亦将拖慢传输速度。 3、奇偶校验 (Parity) 为串口通讯作业错误检查的简易形式。奇偶校验具分为 4 种类型 – Even、Odd、Marked,与 Spaced。亦可不使用奇偶校验。针对 Even 与 Odd,串行端口将设定奇偶校验位 (Parity bit,为数据位之后的最后 1 个位) 为 1 个数值,以确认该传输作业具有逻辑高位 (Logic-high) 位的 Even 或 Odd 数。举例来说,若资料为 011,针对 Even 奇偶校验的奇偶校验位则为 0,才能让逻辑高位位的数字为 Even。在奇偶校验为 Odd 的情况下,奇偶校验位「1」将导致「3」的逻辑高位位。Marked 与 Spaced 的奇偶校验将不会实际检查数据位,但会根据 Marked 奇偶校验设定高的奇偶校验位,或根据 Spaced 奇偶校验设定低的奇偶校验位。此将让接收装置了解位的状态,以进一步判定噪声是否使数据发生中断,或传送与接收装置是否尚未同步化。 2. EIA-232 概述 EIA-232 为 IBM 兼容计算机架构的串口链接功能,可用以连接计算机与传感器/调制解调器,或用于仪器控制等许多功能。EIA-232 硬件可达最长 15 公尺的通讯距离。EIA-232 限用于计算机串行端口与装置之间的点对点连结。因此,计算机往往需要额外的 EIA-232 串行端口。标准计算机 EIA-232 串行端口与许多串行接口的制造商,将试图平衡 Win32 API 于串口通讯函数调用中的功能。Win32 API 原来是设计用于调制解调器通讯作业,且并未建置完整的 EIA-232 协议。基于此项限制,Win32 API 并无法沟通某些装置。

    时间:2020-08-06 关键词: 串口调试 串口

  • esp8266-SDK的串口发送和中断接收

      最近刚开始玩ESP8266这个模块,主要是用在两个ESP8266之间的通信上,进行数据的传输。主要是把两个ESP8266分别配制成AP模式(服务器)和STA模式(客户端)。通过配置从而使其进行通信,由于固件在出厂时已经配置好了,我们这里主要用串口调试助手通过AT指令对需要的一些命令进行配置即可。   ESP8266的基本配置与串口通信   AP模式(服务器):步骤如下   1、AP模式的设置(指令:AT+CWMODE=2);//若以前设置过,这次设置想重新配置,可以通过指令:“AT+RESTORE”进行恢复出厂设置。   2、配置ESP8266的AP参数(指令:AT+CWSAP=《ssid》,《pwd》,《chl》,《ecn》);   3、重启(指令:AT+RST);   4、设置多连接,开启TCP服务器(指令:AT+CIPMUX=1);   5、建立TCP Server(指令:AT+CIPSERVER=1,5000);   6、查询本地IP地址(方便后面的客户端连接用)(指令:AT+CIFSR);   7、发送数据(以上6步完成后,先不写该指令,因为还没有client接入)(指令:AT+CIPSEND=《link.ID》,《length》)   STA模式(客户端):步骤如下   1、STA模式的设置(指令:AT+CWMODE=1);   2、重启(指令:AT+RST);   3、连接AP(指令:AT+CWJAP=《ssid》,《pwd》);   4、建立TCP连接(指令:AT+CIPSTART=《type》,《remote IP》,《remote port》);(该指令执行完成后,可在服务器上配置发送数据指令:AT+CIPSEND)   5、设置传输模式(指令:AT+CIPMODE=1);   6、发送数据(指令:AT+CIPSEND);   以下为AP(服务器)通过串口向STA(客户端)发送信息的事例(每发送一条信息前都需要先发一条指令:AT+CIPSEND=《link.ID》,《length》)   (左边为服务器右边为客户端)(图中发送了两次,所以有16个8)   以下为STA(客户端)通过串口向AP(服务器)发送信息的事例(因为设置成透传模式,所以只需要发送一次指令:AT+CIPSEND,以后再发信息就不用输入指令了。)   (左边为服务器右边为客户端)(连续发送了三次“AT+CIPSEND”和“你好啊”)   esp8266-SDK的串口发送和中断接收   1、发送   调用uart_init(115200,115200);初始化串口,波特率设置为115200.前面一个是设置uart0的波特率、后面一个是设置、uart的波特率   然后就可以使用uart0_tx_buffer(uint8 *buf, uint16 len)从uart0发送数据,同时也可以使用os_printf()函数来发送数据,不过需要注意如果是使用串口1   想要使用os_printf()需要修改   os_printf本接口默认从 UART 0 打印。IOT_Demo 中的 uart_init 可以设置波特率,其中   os_install_putc1((void *)uart1_write_char) 将 os_printf 改为从 UART 1 打印   2、接收   进入串口初始化函数uart_init,可以看到如下函数   system_os_task(uart_recvTask, uart_recvTaskPrio, uart_recvTaskQueue, uart_recvTaskQueueLen);   这个函数是创建一个任务,就是用如处理串口0的接收数据的,   uart_config(UART0);   这就是配置串口寄存器,在这个里面有设置了串口的回调函数   ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));   利用 ETS_UART_INTR_ATTACH设置了串口的回调函数uart0_rx_intr_handler   在uart0_rx_intr_handler里面有各种中断的标志判断,正常的情况会进入UART_RXFIFO_TOUT_INT_ST,也就是,停⽌止传输的时间超过所设定的⻔门   限值,然后调用system_os_post发送消息给在初始化函数uart_init创建的任务uart_recvTask,,然后大家看看uart_recvTask(os_event_t *events)   LOCAL void ICACHE_FLASH_ATTR ///////   uart_recvTask(os_event_t *events)   {   if(events-》sig == 0){   #if UART_BUFF_EN   Uart_rx_buff_enq();   #else   uint8 fifo_len = (READ_PERI_REG(UART_STATUS(UART0))》》UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;   uint8 d_tmp = 0;   uint8 idx=0;   for(idx=0;idx《fifo_len;idx++) {   d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;   uart_tx_one_char(UART0, d_tmp);   }   WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);   uart_rx_intr_enable(UART0);   #endif   }else if(events-》sig == 1){   #if UART_BUFF_EN   //already move uart buffer output to uart empty interrupt   //tx_start_uart_buffer(UART0);   #else   #endif   }   }   在这个里面就是把接收到的数据通过 uart_tx_one_char(UART0, d_tmp);一个个的发送出来,如果我们想处理   自己接收的数据,只要把它放到缓冲区就处理就可以。

    时间:2020-08-05 关键词: esp826 串口

  • 提高keil串口的调试效率的方法

    提高keil串口的调试效率的方法

    做项目要用到单片机的串口的地方的时候,要是有一个有效的提高串口调试的效率调试方案的话,会大大的缩短开发的时间的哦。 运行keil Debug 在命令行加下两句: MODECOM19600,0,8,1 //根据实际情况设置波特率 ASSIGNCOM1SOUT //.......... 然后打开一个串口调试软件,对应串口COM1,9600,0.就可以看到结果了 modecom19600,0,8,1//无校验位,8位数据位,1个停止位 assigncom1sout//意思就是uVision把模拟的单片机串口对应到Serialwindow 和#1上(在serialwindow里输入字符,就是模拟对单片机串口输入数据) modecom19600 assigncom1sout 因为用的本本没有串口,也没法去试试,有空找个台式的试一把哦!o(∩_∩)o...! 1 调试前的准备工作 下面介绍一种利用的功能来实现51单片机用户程序的方法。使用这种方法,无需任何硬件仿真器,甚至都不需要用户电路板。所需的只是: ① 硬件。1台普通计算机(需要带有2个标准串口)和1根串口线(两头都是母头,连线时RXD、TXD要相互交叉)。 ② 串口软件可以是自己编写的专用调试或上下位机通信软件,也可以是通用的串口软件(如串口助手、串口调试等)。 2 基本调试命令介绍 这个串口调试方法主要是利用了Keil强大的软件仿真功能。在新版本(高于6.0)的Keil软件中,增强了软件的仿真能力,可以利用软件仿真更多的单片机功能。在这些功能中,其中有一个很重要的功能就是利用计算机的串口来模拟单片机的串口(这不同于很多软件在仿真时使用的激励文件方式,可以直接与其他串口进行通信,更加方便、灵活)。首先要介绍仿真时需要使用的两个命令:ASSIGN和MODE。 2.1 ASSIGN命令 将单片机的串口绑定到计算机的串口。基本使用方式为: ASSIGN channeloutreg 其中: channel代表计算机的串口,可以是COM1、COM2、COM3或COM4;而inreg和outreg代表单片机的串口。对于只有一个串口的普通单片机,即SIN和SOUT;对于有两个或者多个串口的单片机,即SnIN和SnOUT(n=0,1,…即单片机的串口号)。 图1 串口连线示意图 例如: ASSIGN COM1SOUT 将计算机的串口1绑定到单片机的串口(针对只有一个串口的单片机)。 ASSIGN COM2S0OUT 将计算机的串口2绑定到单片机的串口0(针对有多个串口的单片机,注意串口号的位置)。 需要注意的是,参数的括号是不能省略的,而outreg则是没有括号的。 2.2 MODE命令 设置被绑定计算机串口的参数。基本使用方式为: MODE COMx baudrate, parity, databits, stopbits 其中: COMx(x = 1,2,…)代表计算机的串口号;baudrate代表串口的波特率;parity代表校验方式;databits代表数据位长度;stopbits代表停止位长度。 例如: MODE COM1 9600, n, 8, 1 设置串口1。波特率为9 600,无校验位,8位数据,1位停止位。 MODE COM2 19200, 1, 8, 1 设置串口2。波特率为19 200,奇校验,8位数据,1位停止位。 使用以上两个命令,就能够将计算机的串口模拟成单片机的串口了。在进行时,所有发送到被绑定的计算机串口上的数据都会转发到模拟的单片机串口上,用户程序可以通过中断处理程序或查询方式接收到这些数据;同样,单片机程序中发送到单片机串口上的数据也会通过被绑定的计算机串口发送出来,可以被其他软件所接收。利用这个特点,就可以方便地仿真、调试单片机的串口部分程序。要注意的是,这两个命令需要一起使用。 2.3 仿真步骤 首先,用串口线将计算机的两个串口连接起来(或者是两台计算机上的两个串口)。这两个串口一个用来模拟单片机串口,另一个给调试程序使用。这个由用户自己分配,没有特殊要求。 其次,编写好用户程序,并编译通过。 然后,设置工程文件(Project)的相关参数,如图2和图3所示。主要是选择软件仿真模式(Use Simulator)以及晶振参数。 图2 仿真参数设置 为了不必每次进入仿真状态后,都需要输入串口参数设置命令,可以建立一个初始化文件。初始化文件是一个普通的文本文件,内容就是仿真时需要的命令,按照顺序一行输入一条。如图2所示,建立了一个debug.ini的初始化文件。这样,当每次进入仿真调试状态时,Keil就会自动载入 debug.ini的内容进行初始化。 图3 晶振参数设置 为了正确仿真串口,在软件仿真调试时,在用户的Keil工程文件的属性中,还需要设置实际使用的晶振频率。这个参数非常重要,直接影响通信的波特率,可以按照实际使用的参数进行设置。要注意,这个参数的单位是MHz。 设置好参数后,就可以进行仿真了。单击工具栏的图标按此在新窗口浏览图片进入Debug(仿真调试)状态,在Output window窗口中的command文本框(一般是在左下角)中输入上面介绍的命令。例如,将PC机的串口1设置为单片机的串口: mode com1 9600,0,8,1 assign com1Sout 然后设置断点,一般是在关键地方或与串口相关联的地方设置。再单击图标运行(Run)用户程序,使用户程序运转起来(不然是接收不到串口数据的)。这时再使用软件或用户调试软件,发送通信命令或者数据包,看用户程序是否进入断点,以及相关的变量是否正确。还可以有意发送带有错误数据的数据包,以观察用户程序的异常处理部分是否正常。一旦发现程序中的错误,可以马上停止仿真调试,立即修改代码,然后再次重复上面的步骤进行仿真。因为不需要与用户目标板联机,也不用下载代码到用户板上,所以速度非常高。以上这些步骤和使用硬件仿真器的基本一样,只不过现在使用的是软件仿真。 需要注意的是:仿真时单片机串口实际的波特率由MODE命令来指定,单片机程序中的TMOD、SCON等参数是不影响串口仿真状态的(也就是说这些参数不影响仿真的波特率,即使它们是错误的)。但是中断的使能位(如ES、EA等)还是起作用的,如果ES或EA被禁止,那么就不会进入串口中断。 因为这种方法是利用计算机的串口来仿真单片机的串口,而仿真是通过Keil软件来转换串口上的数据,不是直接转发数据的,所以在实际仿真时,处理速度会比实际单片机运行时稍微低一点。比方说仿真状态时1 s只能发送/接收10个数据帧,但在单片机硬件上运行时可能1 s就可以接收/发送50个数据帧。这与使用的计算机的速度有关,但对仿真来说,是没有任何影响的。 对于多串口的单片机,从理论上来说,可以一次绑定多个串口,只要计算机有足够多的串口。基本上,使用这种方法需要占用计算机的串口数量是单片机绑定串口的2倍。一个串口被Keil占用,用来模拟单片机的串口;另外一个串口被计算机占用,用来给单片机的串口收发数据。 3 小结 这里介绍的方法对C51和汇编语言都是适合的。它最大的好处就是简单、方便,容易使用,不需要使用任何电路,也没有特殊的要求;甚至可以在硬件电路制作好之前就将串口部分的程序编写、调试完毕。笔者使用这种方法已经很长时间了,事实证明这种方法确实非常有效。其实对于51单片机,Keil的仿真功能实在是太强大了,只要充分掌握其特点,能够熟练利用它,就可以解决工作中的大部分问题。很多工作都可以使用软件仿真来完成,根本无需任何硬件仿真器;只有一些新的外部器件的时序、接口的调试才有可能需要用到硬件仿真器。目前介绍Keil软件仿真这方面的参考书籍很少,有些讲的还是老版本的用法,不过没有关系,Keil的帮助文件写得很详细、很清楚,只要认真看明白就会使用了。使用熟练后

    时间:2020-07-17 关键词: keil 串口

  • 民用级激光型PM2.5传感器TF-LP01的应用领域和使用方法

    民用级激光型PM2.5传感器TF-LP01的应用领域和使用方法

    TF-LP01是日本figaro开发的民用级激光型PM2.5传感器,是利用光散射原理对空气中粉尘颗粒进行检测的小型模组,能精准检测到具体PM1.0、PM2.5、PM10的数值,USART(3.3V TTL电平)和PWM(需定制)输出,具备体积小、检测精度高、重复性好、一致性好、实时响应可连续采集、抗干扰能力强、采用超静音风扇,传感器出厂100%检测和标定等优点,适用于各种需要进行PM值检测的场合。 目前,PM2.5传感器TF-LP01已广泛在以下领域得到很好的应用: 1.适用于工矿企业劳动部门生产现场粉尘浓度的测定-煤矿粉尘检测 2.卫生防疫站公共场所可吸入颗粒物的监测3.环境环保监测部门大气飘尘检测,污染源调查 4.市政监烟 5.科学研究,滤料性能试验等方面现场测试 6.现场粉尘浓度测定,排气口粉尘浓度监测 7.药品制造测试 8.职业健康和安全检测 9.工厂需要清洁空气的地方,精密仪器,测试仪器,电子部件,食品,药品等制造工艺的管理 10.各种研究机构,气象学,公众卫生学,工业劳动卫生工程学,大气污染研究等 11.建筑或爆破的地方的粉尘检测,工地场所暴露监测 12.室内空气质量检测,空气净化,例如:空气净化器、空调、抽湿机、新风机或系统,甲醛检测仪、智能家居等 13.车载行业,车内空气检测和净化,移动车载城市空气检测站 PM2.5传感器TF-LP01一方面可以直接通过串口调试助手在电脑上检测数据,一方面可以通过MCU开发在产品应用,使用方法简单介绍如下: PM2.5传感器TF-LP01如何在电脑端进行调试测试,查看数据呢?简单介绍如下: 一、工具准备 TF-LP01传感器(包含连接线)、电脑、串口调试助手、pl2303(USB转串口驱动)、USB 转 TTL 串口线 二、操作使用 1.先在电脑端安装串口调试助手和pl2303驱动; USB 转 TTL 串口线,接上 PM2.5 传感器,插上电脑,传感器引脚定义以及连线方式如下: 传感器1脚为VCC-接转串口中的电源正极 传感器2脚为GND-接转串口中的电源负极 传感器4脚为RXD-接转串口中的TXD 传感器5脚为TXD-接转串口中的RXD 2.通电后,在电脑打开串口调试助手软件,进行串口配置和通讯参数设置 (1)串口号配置 打开电脑设备管理器,了解串口号信息 (2)通讯参数配置,主要设置波特率、校验位、数据位、停止位,(参考例子) 3.点击连接,打开串口,串口调试助手会自动收到传感器上传的收据,单次上传17个字节的16进制数据代码。 4.数据读取方式(读取数据格式如下) 其中测试的PM值主要以滤波后校准值为准,PM1.0值为10~11位,PM2.5为12~13位,PM10值为14~15位,注意的是传感器先上传的是数据低位,所以低位在前,高位在后。从上图3中抽一组数据作为例子来简单介绍:02 09 0E 08 00 02 00 01 00 14 00 1A 00 1C 00 2C 50 测试的PM1.0值为0014,转换为10进制数为:20 ug/m3 测试的PM2.5值为001A,转换为10进制数为:26 ug/m3 测试的PM10值为001C, 转换为10进制数为:28 ug/m3 PM2.5传感器TF-LP01如何结合MCU进行产品电路设计以及注意事项?简单介绍如下: 如果MCU是3.3V供电的,那传感器引脚1接+5VDC,引脚2接地GND,引脚4 RXD接MCU的TXD,引脚5接MCU的RXD,3,7,8脚悬空不接,6脚可以不接,接的话接到MCU的reset,需要接上拉电阻,注意,如果MCU是5V供电,则需要在通讯线(RXD,TXD)上加入电平转换芯片或电路才能和MCU通讯。

    时间:2020-06-09 关键词: 传感器 MCU 串口

  • 工业控制计算机可以有多少个串口

    工业控制计算机可以有多少个串口

    (文章来源:东田工控) 工控机可以有多少个串口?首先我们先来了解下什么是工控机串口?工控机串口是一种在工控机上的接口,连接外部设备,主要用来数据传输数据通信。一般工控机串口可以分为232串口、422串口、485串口三大类。工控机可以有多少个串口?工控机的串口可以主板自带,也可以通过主板上的扩展槽位来扩展。 当然了,工控机能自己带的串口是最好的。为什么这么说呢?因为自带串口在使用过程中比外扩的使用起来更加稳定,基本不会发生故障。但是外扩的会因为连接上的技术问题,出现串口无法接通等情况,从而影响工控机的使用。工控机可以有多少个串口?其实主要还是看工控机的主板,通过自带或者外扩基本能达到客户目前所需要的串口数量。下面我在这里给大家介绍下杭州东田科技有限公司一款多串口的工控机。 产品特征:1、IntelCore四代处理器。2、4*288pinDDR41333/1600/1866/2133MHzECCDDR4DIMM内存插槽,最高支持16G内存。3、8个USB2.0接口、2个USB3.0接口。10个COM接口(2个232/422/485串口、8个232串口)、2个VGA接口、1个HDMI、2个千兆网口、1个PCI-E*16、1个LPT接口,支持数据备份。4、标准配置300W电源,也可以更换400W或者500W冗余电源供电,可以在各类工业环境中使用。        

    时间:2020-05-12 关键词: 工控机 串口

  • 实现USB通信协议和标准串口的设计的注意事项

    基于卫星的 NB-IoT 网络和企业自建私有 NB-IoT 网络,都是通过扩大物联网连接方式,实现“连接未连接的物”,扩大 5G 大连接的范畴,尽量使物联网通信技术覆盖所有场景。 笔者曾在《2020 全国物联网全景图谱报告》前言中提到,物联网通信技术正在“扩大连接范围,连接未连接的物”。过去几年中,NB-IoT 作为专用于物联网的通信技术,除了由主流运营商部署外,也在不断扩大部署形式,扩展运营商 NB-IoT 不能覆盖的范畴,力求做到大部分低功耗、大连接的远距离物联网场景都有相应连接方案。 基于卫星的 NB-IoT NB-IoT 一个新的扩展方向是向天基物联网发展,即通过卫星提供全球无处不在的 NB-IoT 网络,这样不论身处海洋还是深山中,都可以实现物联网连接。 初创公司 Skylo Technologies 为全球物联网用户提供泛在连接服务,其中一个亮点是计划于 2020 年夏季推出基于卫星的全球化 NB-IoT 网络,这一 NB-IoT 网络旨在为移动性设备提供服务,主要应用于农业、交通、航海、应急等领域。Skylo 公司成立于 2017 年,并于当年年底获得三家机构 1300 万美元的 A 轮融资,其中一家机构是谷歌前 CEO Eric Schmidt 的风投公司;近日,该公司又获得了软银领投的 1.03 亿美元的 B 轮投资。 Skylo 公司基于卫星的 NB-IoT 网络是采用地球同步通信卫星连接 Skylo 部署在地球上的网关,网络运行频段除了专门的同步卫星通信业务频段外,也运行在 3GPP 所定义的频段上。这是一个双向通信的网络,除了网关将数据回传给卫星外,由于专有的天线技术,卫星无需额外设备也可以将数据反馈至网关。其中,那些网关是 8*8 英寸的盒子,一般安装在渔船、火车车厢以及其他场景设备上,网关盒子作为收发器,收集本地传感器数据,并通过卫星网络将数据传输至云端平台。   目前已有大量卫星通信的方案,但卫星通信一般成本很高,而这张 NB-IoT 网络成本并不高。根据 Skylo 公司 CEO 所述,该网络连接成本比现有卫星通信方案节约 95%的成本。具体来说,该网络连接资费大约为每个用户每月 1 美元,硬件成本即网关低于 100 美元。Skylo 公司的卫星 NB-IoT 网络首先在印度提供服务,首家客户是印度铁路公司,印度铁路公司将在其车厢安装 Skylo 的网关,使用 Skylo 的 NB-IoT 网络。   根据 GSMA 发布的数据,截止 2020 年 1 月,全球已有 92 张商用 NB-IoT 网络。在全球主流运营商都部署 NB-IoT 网络的同时,基于卫星的 NB-IoT 网络正在践行着“连接未连接物”的使命,一方面对运营商蜂窝网络形成补充,另一方面在一定程度上也和蜂窝网络形成竞争。 实际上,Skylo 并非独家提供卫星 NB-IoT 的厂商,美国另一家物联网公司 Ligado Networks 表示其准备在 1500MHz-1700MHz 频段上使用 NB-IoT 标准建设一个卫星网络;卢森堡一家名为 OQ Technology 的公司已经在一些商业卫星上测试软件定义无线电(SDR)的 NB-IoT 无线接入。除此之外,我们也看到近年来大量初创公司均推出廉价的低轨卫星物联网方案,国内也有数家民营卫星公司推动卫星物联网进展,当然国内还未出现基于卫星的 NB-IoT 网络。 私有 NB-IoT 网络 GSMA 所公布的截止 1 月有 92 张 NB-IoT 网络商用,这些网络均为主流运营商向所在区域提供的公共物联网网络,而随着 NB-IoT 逐渐成熟,私有 NB-IoT 网络开始出现,为一些关键行业提供更为安全可靠的保障。 2019 年 6 月,位于美国加州的一家名为 Puloli 的公司宣布推出首个私有 NB-IoT 网络,该网络采用 700MHz 频谱,部署在佛罗里达北部,基本覆盖该地区大多数人口,是为该地区一家公用事业企业提供部署的。对于私有网络,Puloli 探索出一套网络即服务(NaaS)的商业模式,负责网络设计、部署和运营。除了网络服务外,该私有 NB-IoT 网络采用 Pycom 公司基于 Sequans Monarch 芯片的 NB-IoT 模组,该模组支持 700MHz 频段。   由于是私有网络,Puloli 对此进行专门的频段定制,在 700MHz 频段中使用 1MHz 作为下行,另外 1MHz 作为上行。当然,由于 700MHz 频段已经被 21 家基础设施机构购买,包括电力、燃气、水务、石油以及铁路公司,因此频谱是部署私有网络最具挑战的环节。Puloli 与一家名为 Select Spectrum 的频谱咨询机构合作,该机构为无线电频谱的买卖提供规划、咨询和数据分析服务,最终确定频谱定制方案。 部署私有网络并非一件新鲜事物,在移动通信发展的各个历史阶段,都有很多重点行业和重点企业基于自身业务的需要,自建或者委托建设一张归属于自己的私有网络,与运营商提供的公共网络做到物理上的隔离来保障安全性。因此,在全球主流运营商积极部署 NB-IoT 公共网络的同时,NB-IoT 私网也开始出现,也是一个正常的现象。   当然,从目前发展情况看,NB-IoT 私网并未形成一个大量部署的态势。实际上,早在 2016 年 6 月 NB-IoT 标准冻结之初,华为就推出了基于 NB-IoT 的私网方案 eLTE-IoT,华为企业网官方微信对此做出以下描述:   eLTE-IoT 解决方案是为企业自建的免授权物联网市场,提供基于 Sub-GHz 免授权频谱的低功耗中长距物联网无线技术。针对低数据速率、大规模终端数目及广覆盖要求等典型的 M2M 应用场景,eLTE-IoT 可以为政企等行业客户,如智慧城市、电力和燃气 / 水务厂商开辟广阔的物联网市场。eLTE-IoT 的芯片将完全重用 3GPP NB-IoT 的芯片,和免授权频谱上的 LTE 技术类似,eLTE-IoT 产业链的参与者,也是 3GPP NB-IoT 的玩家。   既然能够复用 NB-IoT 本身产业生态,那么随着 NB-IoT 产业的发展,NB-IoT 私网产业链也会准备就绪。不过,除了产业链外,需求、商业模式等方面也需要准备就绪。近年来,仅电力等少数行业中有 NB-IoT 私有网络的应用。   在当前 5G 快速发展的背景下,NB-IoT 已纳入 5G mMTC 候选标准中。此前,全球多国和大量行业都在探索发展 5G 私网,不少国家也开始为企业建设 5G 私网分配频谱,形成 5G 赋能行业的一种典型的形式。企业自建 5G 私网,在很大程度上用于物与物的通信,连接企业各类物联网设备,而其中低功耗、大连接的部分将由 NB-IoT 来承载。从这个角度来看,未来 NB-IoT 私有网络更多是通过 5G 私网来呈现。   不论是基于卫星的 NB-IoT 网络,还是企业自建私有 NB-IoT 网络,都是通过扩大物联网连接方式,实现“连接未连接的物”,扩大 5G 大连接的范畴,尽量使物联网通信技术覆盖所有场景。

    时间:2020-05-07 关键词: 通信 USB 串口

  • c51 串口 波特率的计算

    在串行通信中,收发双方对发送或接收的数据速率要有一定的约定,我们通过软件对MCS—51串行口编程可约定四种工作方式。其中,方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定时器T溢出率决定。 串行口的四种工作方式对应着三种波特率。由于输人的移位时钟的来源不同,所以,各种方式的波特率计算公式也不同。 一、方式0的波特率 方式0时,移位时钟脉冲由56(即第6个状态周期,第12个节拍)给出,即每个机器周期产生一个移位时钟,发送或接收一位数据。所以,波特率为振荡频率的十二分之一,并不受 PCON寄存器中SMOD的影响,即: 方式0的波特率=fosc/12   三、方式l和方式3的波特率 方式1和方式3的移位时钟脉冲由定时器T1的溢出率决定,故波特宰由定时器T1的 溢出率与SMOD值同时决定,即: 方式1和方式3的波特率=2SMOD/32·T1溢出率 其中,溢出率取决于计数速率和定时器的预置值。计数速率与TMOD寄存器中C/T的状态有关。当C/T=0时,计数速率=fosc/2;当C/T=1时,计数速率取决于外部输入时钟频率。 当定时器Tl作波特率发生器使用时,通常选用可自动装入初值模式(工作方式2),在 工作方式2中,TLl作为计数用,而自动装入的初值放在THl中,设计数初值为x,则每过“256一x”个机器周期,定时器T1就会产生一次溢出。为了避免因溢出而引起中断,此时应禁止T1中断。这时,溢出周期为:   系统晶振频率选为11.0592MHZ就是为了使初值为整数,从而产生精确的波特率。 如果串行通信选用很低的波特率,可将定时器Tl置于工作方式0或工作方式1,但在 这种情况下,T1溢出时,需用中断服务程序重装初值。中断响应时间和执行指令时间会使波特率产生一定的误差,可用改变初值的办法加以调整。 表6—2列出了各种常用的波特率及其初值。  

    时间:2019-08-04 关键词: C51 波特率 串口

  • CC2530 串口驱动

    使用IAR驱动CC2530的串口0,串口1,实现数据发送以及printf,中断接收数据uart.c/*************************************************************************************************************  * 文件名: uart.c  * 功能: CC2530 串口相关函数  * 作者: cp1300@139.com * 创建时间: 2013-06-07 21:33  * 最后修改时间:2013-06-07  * 详细: 串口相关函数 串口最大时钟为系统时钟的1/16 *************************************************************************************************************/ #include "system.h" #include "uart.h" //相关UART状态结构 typedef struct { u8 BuffFull; //接收Buff满 u8  *RxBuff; //接收Buff指针 u16 RxBuffSize; //接收缓冲区大小,一帧数据大小 u16  UartRxCnt; //接收数据计数器 } UartRx_TypeDef; static UartRx_TypeDef UART_RX[2]; static const u8 BAUD_M[11] = {59, 59, 59, 216, 59, 216, 59, 216, 59, 216, 216}; //32MHZ系统时钟对应的分频器小数部分 static const u8 BAUD_E[11] = {6, 7 ,8, 8, 9, 9, 10, 10, 11, 11, 12};                //32MHZ系统时钟对应的分频器指数部分 /************************************************************************************************************************* *函数        :     void UART_Init(UART_CH ch, USART_BAUD Baud, FunctionalState RxIntEn) *功能        : 串口初始化 *参数        :     ch:通道选择,UART_CH0,UART_CH1 Baud:波特率控制,见USART_BAUD RxIntEn:ENABLE:使能串口接收中断 *返回        :    无 *依赖        : 底层宏定义 *作者        : cp1300@139.com *时间        : 2013-05-20 *最后修改时间: 2013-06-11 *说明        : 一个起始位,8个数据位,一个停止位,无奇偶校验 需要开启全局中断 *************************************************************************************************************************/ void UART_Init(UART_CH ch, USART_BAUD Baud, FunctionalState RxIntEn) { switch(ch) { case UART_CH0: { U0CSR = BIT7 + BIT6; //UART模式,使能接收 U0UCR = BIT1; //无流控,无奇偶校验,8bit,1个停止位,停止位高电平,起始低电平 U0GCR =  BAUD_E[Baud]; //波特率分频器指数部分 U0BAUD =  BAUD_M[Baud]; //波特率分频器小数部分 P0SEL |= BIT2 + BIT3;  //P0.3 TXD,P0.2 RXD IEN2 &= ~(1 << 3); //关闭发送中断 URX0IF = 0; //清除串口接收中断标志 UTX0IF = 0; //清除串口发送中断标志 URX0IE = (RxIntEn == ENABLE) ? 1 : 0;   //使能串口接收中断 }break; case UART_CH1: { U1CSR = BIT7 + BIT6; //UART模式,使能接收 U1UCR = BIT1; //无流控,无奇偶校验,8bit,1个停止位,停止位高电平,起始低电平 U1GCR =  BAUD_E[Baud]; //波特率分频器指数部分 U1BAUD =  BAUD_M[Baud]; //波特率分频器小数部分 P1SEL |= BIT4 + BIT5;  //P0.5 TXD,P0.4 RXD URX1IF = 0; //清除串口接收中断标志 UTX1IF = 0; //清除串口发送中断标志 URX1IE = (RxIntEn == ENABLE) ? 1 : 0;   //使能串口接收中断 }break; default : return; } UART_SetRxBuff(ch, NULL, 0); //初始化串口缓冲区无效 } /************************************************************************************************************************* *函数         : void UART_SendByte(UART_CH ch, u8 data) *功能         : UART字节发送函数 *参数         : ch:通道选择,UART_CH0,UART_CH1 data:需要发送的数据 *返回         : 无 *依赖         : 底层宏定义 *作者         : cp1300@139.com *时间         : 2013-06-11 *最后修改时间 : 2013-06-11 *说明         : 无 *************************************************************************************************************************/ void UART_SendByte(UART_CH ch, u8 data) { switch(ch) { case UART_CH0: { U0DBUF = data;         //发送字节数据 while(!(U0CSR & BIT1)); //等待发送数据寄存器为空 U0CSR &= ~BIT1; }break; case UART_CH1: { U1DBUF = data;         //发送字节数据 while(!(U1CSR & BIT1)); //等待发送数据寄存器为空 U1CSR &= ~BIT1; }break; default : break; } } /************************************************************************************************************************* *函数         : void UART2_SendData(u8 *pbuff, u16 len) *功能         : 串口发送任意长度数据 *参数         : ch:通道选择,UART_CH0,UART_CH1 pbuff:数据缓冲区指针,len:数据长度 *返回         : 无 *依赖         : 底层宏定义 *作者         : cp1300@139.com *时间         : 2013-06-11 *最后修改时间 : 2013-06-11 *说明         : 无 *************************************************************************************************************************/ void UART_SendData(UART_CH ch, u8 *pbuff, u16 len) { u16 i; switch(ch) { case UART_CH0: { for(i = 0;i < len;i ++) { U0DBUF = pbuff[i];         //发送字节数据 while(!(U0CSR & BIT1)); //等待发送数据寄存器为空 U0CSR &= ~BIT1; } }break; case UART_CH1: { for(i = 0;i < len;i ++) { U1DBUF = pbuff[i];         //发送字节数据 while(!(U1CSR & BIT1)); //等待发送数据寄存器为空 U1CSR &= ~BIT1; } }break; default : break; } } /************************************************************************************************************************* * 函数 : void UART2_SendString(UART_CH ch, const char *pStr) * 功能 : UART发送字符串 * 参数 : ch:通道选择,UART_CH0,UART_CH1 pStr:字符串指针 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  遇到'0'后停止发送 *************************************************************************************************************************/ void UART_SendString(UART_CH ch, const char *pStr) { while(*pStr != '') { UART_SendByte(ch, *pStr ++); } } /************************************************************************************************************************* * 函数 : void UART_RxEnable(UART_CH ch, FunctionalState Enable) * 功能 : UART接收使能 * 参数 : ch:通道选择,UART_CH0,UART_CH1 Enable:ENABLE:使能接收,DISABLE:取消接收 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  无 *************************************************************************************************************************/ void UART_RxEnable(UART_CH ch, FunctionalState Enable) { switch(ch) { case UART_CH0: { U0CSR = (Enable == ENABLE) ? (U0CSR|BIT6) : (U0CSR&(~BIT6)); //使能接收 }break; case UART_CH1: { U1CSR = (Enable == ENABLE) ? (U1CSR|BIT6) : (U1CSR&(~BIT6)); //使能接收 }break; default : break; } } //UART0中断服务程序 #pragma vector=URX0_VECTOR __interrupt void UART0_IRQHandler(void) { if(UART_RX[0].RxBuffSize > 0) { UART_RX[0].RxBuff[UART_RX[0].UartRxCnt ++] = U0DBUF;  if(UART_RX[0].UartRxCnt == UART_RX[0].RxBuffSize) {  UART_RX[0].UartRxCnt = 0;  UART_RX[0].BuffFull = 1; } } else { URX0IF = 0; //清除串口接收中断标志 } } //UART1中断服务程序 #pragma vector=URX1_VECTOR __interrupt void UART1_IRQHandler(void) {     if(UART_RX[1].RxBuffSize > 0) { UART_RX[1].RxBuff[UART_RX[1].UartRxCnt ++] = U1DBUF;  if(UART_RX[1].UartRxCnt == UART_RX[1].RxBuffSize) {  UART_RX[1].UartRxCnt = 0;  UART_RX[1].BuffFull = 1; } } else { URX1IF = 0; //清除串口接收中断标志 } } /************************************************************************************************************************* * 函数 : bool UART_GetNewData(UART_CH ch, u8 *pData) * 功能 : 获取串口新数据 * 参数 : ch:通道选择,UART_CH0,UART_CH1 pData:数据缓冲区指针 * 返回 : TRUE:有新数据,FALSE:无新数据 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  用于非中断模式下获取串口新数据 *************************************************************************************************************************/ bool UART_GetNewData(UART_CH ch, u8 *pData) { switch(ch) { case UART_CH0: { if(U0CSR & BIT2) { *pData = U0DBUF; return TRUE; } return FALSE; }break; case UART_CH1: { if(U1CSR & BIT2) { *pData = U1DBUF; return TRUE; } return FALSE; }break; default : return FALSE; } } /************************************************************************************************************************* * 函数 : bool UART_GetRxBuffFullFlag(UART_CH ch) * 功能 : 获取串口接收缓冲区满标志 * 参数 : ch:通道选择,UART_CH0,UART_CH1 * 返回 : TRUE:满,FALSE:没有满 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  : 2013-06-11 * 说明 :  用于判断接收缓冲区是否满,会清除标志 *************************************************************************************************************************/ bool UART_GetRxBuffFullFlag(UART_CH ch) { if(UART_RX[ch].BuffFull) //缓冲区已满 {   UART_RX[ch].BuffFull = 0; //清除满标志 return TRUE; } return FALSE; } /************************************************************************************************************************* * 函数 : void UART_SetRxBuff(UART_CH ch, u8 *pRxBuff, u16 BuffSize) * 功能 : 设置串口接收缓冲区 * 参数 : ch:通道选择,UART_CH0,UART_CH1 pRxBuff:缓冲区指针,BuffSize:缓冲区大小 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  用于中断接收 *************************************************************************************************************************/ void UART_SetRxBuff(UART_CH ch, u8 *pRxBuff, u16 BuffSize) { UART_RX[ch].RxBuffSize = BuffSize;  //设置缓冲区大小 UART_RX[ch].RxBuff = pRxBuff; //设置缓冲区指针 UART_RX[ch].UartRxCnt = 0; //计数器清零 } /************************************************************************************************************************* * 函数 : u16 UART_GetRxCnt(UART_CH ch) * 功能 : 获取串口接收数据计数器 * 参数 : ch:通道选择,UART_CH0,UART_CH1 * 返回 : 接收到的数据数量 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  无 *************************************************************************************************************************/ u16 UART_GetRxCnt(UART_CH ch) { return UART_RX[ch].UartRxCnt; //返回计数值 } /************************************************************************************************************************* * 函数 : void UART_ClearRxCnt(UART_CH ch) * 功能 : 清除串口接收数据计数器 * 参数 : ch:通道选择,UART_CH0,UART_CH1 * 返回 : 无 * 依赖 : 底层宏定义 * 作者 : cp1300@139.com * 时间 : 2013-06-11 * 最后修改时间  :  2013-06-11 * 说明 :  无 *************************************************************************************************************************/ void UART_ClearRxCnt(UART_CH ch) { UART_RX[ch].UartRxCnt = 0; //计数器清零 }uart.h/*************************************************************************************************************  * 文件名: uart.h  * 功能: CC2530 串口相关函数  * 作者: cp1300@139.com * 创建时间: 2013-06-07 21:33  * 最后修改时间:2013-06-07  * 详细: 串口相关函数 *************************************************************************************************************/ #ifndef _UART_H_ #define _UART_H_ #include "system.h" #include "stdio.h" //串口波特率定义 typedef enum { BAUD_2400  = 0, //2400 BAUD_4800  = 1, //4800 BAUD_9600  = 2, //9600 BAUD_14400  = 3, //14400 BAUD_19200  = 4, //19200 BAUD_28800  = 5, //28800 BAUD_38400  = 6, //38400 BAUD_57600  = 7, //57600 BAUD_76800  = 8, //76800 BAUD_115200 = 9, //115200 BAUD_230400 = 10, //230400 } USART_BAUD; //串口通道选择 typedef enum { UART_CH0 = 0, //通道0,串口0 UART_CH1 = 1, //通道1,串口1 } UART_CH; //UAR void UART_Init(UART_CH ch, USART_BAUD Baud, FunctionalState RxIntEn); //UART初始化 void UART_SendByte(UART_CH ch, u8 data); void UART_SendData(UART_CH ch, u8 *pbuff, u16 len); //串口发送任意长度数据 void UART_SendString(UART_CH ch, const char *pStr);  //UART发送字符串 void UART_RxEnable(UART_CH ch, FunctionalState Enable); //UART接收使能 bool UART_GetNewData(UART_CH ch, u8 *pData); //获取串口新数据 bool UART_GetRxBuffFullFlag(UART_CH ch); //获取串口接收缓冲区满标志 void UART_SetRxBuff(UART_CH ch, u8 *pRxBuff, u16 BuffSize); //设置串口接收缓冲区 u16 UART_GetRxCnt(UART_CH ch); //获取串口接收数据计数器 void UART_ClearRxCnt(UART_CH ch); //清除串口接收数据计数器    #endif //_UART_H_//重定义printf到串口#if _PRINTF_EN_ #include "uart.h" #include "stdio.h" //#define __CODE_MODEL__ = __CM_BANKED__ __near_func int putchar(int ch) { UART_SendByte(UART_CH0, ch); return ch; } #endif初始化//主函数 int main(void) {     SYS_ClockInit();     UART_Init(UART_CH0, BAUD_115200,ENABLE);     LED_Init();     clock_init();     SYS_EnableInt();     process_init(); process_start(&etimer_process, NULL); autostart_start(autostart_processes); printf("Processes runningn"); while(1) { do { } while(process_run()> 0); SYS_PowerIdle();            //空闲模式 } }

    时间:2019-07-02 关键词: printf 串口

  • MAX232和PL2303、CH340的区别

    MAX232和PL2303、CH340的区别

    原理:单片机的TXD、RXD是TTL电平,所以你得万变不离其宗的将其它信号转成TTL电平,只有这样给单片机下载程序才有可能成功!其中CH340、PL2303等芯片是直接将USB信号转换为TTL电平或者TTL电平转换为USB信号,而MAX232等芯片是将TTL转换为RS232信号或者将RS232信号转换为TTL. MAX232:外围电路简单,但是占用pcb面积大,不美观 PL2303:水货多不稳定,外围电路复杂,成本低 CH340:稳定,外围电路简单,成本相对高 CH340典型电路图 计算机和MCU通信的方法: 1.只有串口接口的台式机(很老) 交叉串口线>>>MAX232芯片>>>MCU(单片机) 2.既有串口接口又有USB接口的电脑(台式机) (1)电脑串口接口>>>交叉串口线>>>MAX232芯片>>>MCU(单片机) (2)电脑USB接口>>>USB转串口线>>>MAX232芯片>>>MCU(单片机) (3)电脑USB接口>>>USB2.0数据线>>>PL2303或CH340>>>MCU(单片机) 3.只有USB接口的电脑(笔记本) (1)电脑USB接口>>>USB转串口线>>>MAX232芯片>>>MCU(单片机) (2)电脑USB接口>>>USB2.0数据线>>>PL2303或CH340>>>MCU(单片机) 计算机和MCU通信的原理: (1)交叉串口线原理:信号线交叉,导线作用 (2)USB转串口线原理:USB接口>>>PL2303或CH340>>>MAX232>>>9针接口 (3)USB2.0数据线原理:信号线直连,导线作用 信号分析: 电脑串口接口>>>电脑输出232电平信号>>>MAX232芯片>>>TTL电平 电脑USB接口>>>电脑输出USB电平信号>>>USB转串口线>>>232电平信号>>>MAX232芯片>>>TTL电平 电脑USB接口>>>电脑输出USB电平信号>>>PL2303或CH340芯片>>>TTL电平

    时间:2019-06-02 关键词: 通信 基础教程 信号转换 串口

  • 为了爽快地调试硬件,我跟串口调试助手杠上了

    为了爽快地调试硬件,我跟串口调试助手杠上了

    本文来自于知乎「厄兰德森」投稿, 感谢作者的分享嵌入式ARM欢迎各位投稿编辑:付斌跟嵌入式硬件打过交道的人都知道,在调试硬件时,经常要用到上位机、下位机联合调试。串口助手是应用最广泛的调试上位机,简单的调试需求,比如仅仅是看一眼程序的执行结果,调试助手可以应付的,简单方便,拿起就用。但遇到稍微复杂一点的调试需求时,串口助手就满足不了要求了。举个例子,调试PID算法的时候,需要实时观测传感器的数据曲线特征,实时调整比例、积分、微分3个参数,没有人会想用串口助手来调试。来自日本的primer v2机器人,靠PID算法控制平衡很多人在遇到复杂的调试需求时,会选择自己编写上位机。对于不懂得上位机编程又找不到合适工具的人,往往选择串口助手凑合着用。一个合格的嵌入式硬件调试工具,其实应该更贴心一点,在不增加使用难度的情况下,让即使不懂得上位机编程的开发者,也能直观地观测数据、微调参数。另外,调试助手作为一个辅助工具,不能增加用户的学习成本,需要像串口助手一样简单易用。于是笔者有了自己编写一个通用调试工具的想法。“伏特+”,寓意名酒伏特加,之前跟朋友开过一个玩笑,说喝酒之后,编程特别有灵感。因此我将整个软件也设计成默认蓝色伏特加鸡尾酒的风格,主题颜色可以根据用户喜好,通过拖动滑块进行修改,每个用户就像调酒师一样,喜欢什么口味的伏特加自己调,希望这个软件拥有鸡尾酒的功效,能提高各位开发者的调试效率。伏特加拥有统计功能、支持条形图、直方图、频域图显示。不仅支持二维调试、还支持三维调试。伏特加还有开放性的特点,用户可以添加自定义控件,通过图形化界面的方式在线修改程序参数,查看数据结果。自定义控件的源码是开源的,用户可以根据需要自己编写自定义控件。软件不仅支持2维调试,还支持3维调试,用户可动态添加控件。自定义控件源码开源,可动态插入,用户可以根据现有的例子编写自己的控件。软件不仅支持2维调试,还支持3维调试,用户可动态添加控件。自定义控件源码开源,可动态插入,用户可以根据现有的例子编写自己的控件。下面是这个软件更详细的功能介绍:  1. 支持网络、串口调试两种调试方式,普通调试助手具备的十六进制、字符串调试功能也依然具备。  2.  能图形化(波形图、条形图)显示硬件发送的数据,并且图形可以随意放大缩小移动,能对数据进行简单分析(直方统计、频率分析),并且图形化显示。发送了4组数据,生成了4个波形,4组控件波形小图显示模式波形图+条形图模式波形图+直方统计图模式波形图+频谱图模式,图中波形由频率为2Hz、4Hz,直流分量为0,幅值为1的2个正弦波组成缓冲区大小、显示区大小,缓冲区上限,可以通过拖动滑块来控制  3. 支持添加自定义图形控件,方便用户以图形化的方式, 调整程序参数,查看数据状态。小方框是为了方便配置,在控件锁定后会消失状态灯周围的小方框是为了方便配置,在控件锁定后会消失  4. 接收到数据和自定义的控件,可以保存。数据可以很方便地转移到Matlab等专业数学软件做进一步分析,控件可以下次载入继续使用。软件的运营方面,是通过攒贡献兑换激活时间,贡献的来源包括在线捐赠开发者、提交功能建议、了解广告等形式,而自定义控件是开源的,也欢迎有能力的开发者为大家贡献控件代码,被接纳的开发者将获得永久激活权限。有兴趣获取软件的朋友,可以前往百度网盘下载:https://pan.baidu.com/s/1yNC56G5zKkhWI5laRmoX7Q自定义控件的github如下,在这里会继续给伏特加增加控件,有能力的小伙伴也欢迎贡献代码。https://github.com/je00/Vodka

    时间:2019-04-29 关键词: 嵌入式 串口

首页  上一页  1 2 3 4 5 6 7 8 9 10 下一页 尾页
发布文章

技术子站

更多

项目外包