-
用电脑控制单片机工作——用VB和单片机开发串行通信软件[1]
2010-01-31 19:02:55Visual Basic(简称VB)是Windows操作系统下简 单,易学,高效的应用软件开发工具,已广泛地应用于 各个领域,在微机串口方面也有很强的功能。很多情况 下我们需要把工程技术领域中系统采集的数据交给计 -
利用vb编写的上位机软件使电脑和单片机通信
2011-02-09 19:49:36描述了利用vb编写的上位机软件使电脑和单片机通信,不清楚的同学可以电话我。我这个只是实现原理上的通信。13488158634 -
一、电脑端实现单片机与ESP8266的通信
2019-07-02 10:14:32软件:keil uv4单片机软件、STC-ISP烧录软件、串口调试助手:SSCOM或ATK-XCOM、TCP/UDP调试助手:SocketTool或网络调试助手。 #2.实验步骤 (1)先将ESP8266-01和TTL-USB串口连接,再接上电脑,下面...#1.准备工具(硬件、软件)
硬件:51单片机开发板、ESP8266无线模块(ESP8266-01)、TTL-USB串口、杜邦线、数据线;
软件:keil uv4单片机软件、STC-ISP烧录软件、串口调试助手:SSCOM或ATK-XCOM、TCP/UDP调试助手:SocketTool或网络调试助手。
#2.实验步骤
(1)先将ESP8266-01和TTL-USB串口连接,再接上电脑,下面是接线图,通过电脑来检测无线模块的通信是否正常。
ESP8266-01
TTL-USB
TXD
RXD
RXD
TXD
CH_PD、VCC
3.3V或5V(会很烫,容易烧坏)
GND
GND
(2)AT指令测试
AP模式:1)ESP8266作Server端,电脑作Client端。(本实验方式)
在按上述方式连接电脑后,打开ATK-XCOM调试助手,按照顺序输入以下指令,如果每条指令都返回OK,则证实指令成功。
AT+RST,返回OK(这是重启模块,开始执行指令);
AT+CWMODE=3 或 AT+CWMODE=2,返回OK(1-Station模式, 2-AP模式, 3-AP兼Station模式);
AT+CWSAP="wifi_yuan","123456789",11,4,返回OK(该指令在AP模式开启后生效);
AT+CIPMUX=1,返回OK(0-单路连接模式, 1-多路连接模式);
AT+CIPSERVER=1,8080,返回OK(0-关闭server模式,1-开启server模式);
接着打开SocketTool软件,选择Client,填端口号,模块地址。
2)ESP8266作客户端,电脑端作服务端(补充)
关闭 server 服务 (如果没有开启 server 服务,可免除此步骤)
发送命令: AT+CIPSERVER=0(设置指令)
创建服务器
点击 Listening,变成红色就可以了。
发送命令: AT+CIPMUX=1(开启多连接模式)
建立 TCP 连接
发送命令 AT+CIPSTART=2,"TCP","192.168.4.101",8080 (设置指令)向服务器发送数据
发送命令 AT+CIPSEND=2,8(设置指令) (通过上一条指令 AT+CIPSTART 设置为 ID=2)(3)实验操作。
1)单片机连接ESP8266模块,TXD接RXD,RXD接TXD,3.3V接CH_PD、VCC,GND接GND,STC89C52的引脚图可以百度,也可以用其他芯片。
2)用keil uv4软件编译程序,操作用法自己百度,把程序生成hex文件后,用STC-ISP烧入单片机,记得烧写程序时,把ESP8266的VCC接口拔下,防止影响程序烧入单片机。当程序烧入单片机后,连接好ESP8266,会在ATK-XCOM助手中生成程序中的AT指令,此时通过AP模式1)方式连接,电脑连接ESP8266的wifi,这时在SocketTool或网络调试助手中输入GP 0,红灯亮,接收区为ATK-XCOM,显示红灯亮字样,GP 1,红灯灭,GP 2,绿灯亮,GP 2,绿灯灭,还有黄灯等,根据程序的指令操作LED的灯亮灭。
(4)程序
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit LED0=P1^0; //红灯
sbit LED1=P1^2; //绿灯
sbit LED2=P1^4; //黄灯
/*****************相关变量**************/
uchar Receive,i,qj,yz,zz,ht;
uint n;
uchar Recive_table[40]; //用于接收wifi模块反馈到MCU上的数据
/*******************************************************************
名称:延时函数 作用:毫秒级延时,微妙级延时函数,为数据收发完成作等待.......
********************************************************************/
void ms_delay(uint t)
{
uint i,j;
for(i=t;i>0;i--)
for(j=110;j>0;j--);
}
void us_delay(uchar t)
{
while(t--);
}
void Uart_Init() //使用定时器1作为波特率发生器(STC89C52、STC89C51、AT89C51等均可)
{
TMOD = 0x20;
SCON = 0x50; //设置串行方式
TH1 = 0xFD; //波特率9600
TL1 = TH1;
PCON = 0x00;
EA = 1; //总中断打开
ES = 1; //开串口中断
TR1 = 1; //启动定时器1
}
/********************************************************************
名称:串口发送函数 功能:MCU向无线WIFI模块ESP8266发送数据
********************************************************************/
void Send_Uart(uchar value)
{
ES=0; //关闭串口中断
TI=0; //清发送完毕中断请求标志位
SBUF=value; //发送
while(TI==0); //等待发送完毕
TI=0; //清发送完毕中断请求标志位
ES=1; //允许串口中断
}
/********************************************************************
名称:WIFI模块设置函数 作用: 启动模块,以便可以实现无线接入和控制
********************************************************************/
void ESP8266_Set(uchar *puf) // 数组指针*puf指向字符串数组
{
while(*puf!='\0') //遇到空格跳出循环
{
Send_Uart(*puf); //向WIFI模块发送控制指令。
us_delay(5);
puf++;
}
us_delay(5);
Send_Uart('\r'); //回车
us_delay(5);
Send_Uart('\n'); //换行
}
/********************************************************************
名称:WIFI模块发送函数 作用: 启动模块,以便可以实现无线接入和控制
********************************************************************/
void ESP8266_Sent(uchar *puf) // 数组指针*puf指向字符串数组
{
ESP8266_Set("AT+CIPSEND=0,26");
while(*puf!='\0') //遇到空格跳出循环
{
Send_Uart(*puf); //向WIFI模块发送控制指令。
us_delay(5);
puf++;
}
us_delay(5);
Send_Uart('\n'); //换行
ms_delay(10);
}
/********************************************************************
名称:主函数 作用:程序的执行入口
********************************************************************/
void main()
{
Uart_Init();
ms_delay(2000);
ESP8266_Set("AT+RST"); //波特率发生器
ms_delay(2000);
ESP8266_Set("AT+CWMODE=2"); //设置路由器模式1 station,模式2 AP,模式3 station+AP混合模式
//ms_delay(2000);
//ESP8266_Set("AT+RST"); //重新启动wifi模块
ms_delay(2000);
ESP8266_Set("AT+CWSAP=\"wifi_yuan\",\"123456789\",11,4"); //AT+CWSAP="wifi_yuan","123456789",11,4 设置模块SSID:WIFI, PWD:密码 及安全类型加密模式(WPA2-PSK)
ms_delay(2000);
ESP8266_Set("AT+CIPMUX=1"); //开启多连接模式,允许多个各客户端接入
ms_delay(2000);
ESP8266_Set("AT+CIPSERVER=1,8080"); //启动TCP/IP 实现基于网络//控制 ESP8266_Set("AT+CIPSERVER=1,5000");
ms_delay(2000);
ESP8266_Set("AT+CIPSTO=0"); //永远不超时
ES=1; //允许串口中断
qj=1;
zz=1;
yz=1;
ht=1;
LED0=1;
LED1=1;
LED2=1;
while(1)
{
if((Recive_table[0]=='+')&&(Recive_table[1]=='I')&&(Recive_table[2]=='P')&&(Recive_table[3]=='D'))//MCU接收到的数据为+IPD时进入判断控制0\1来使小灯亮与灭
{
if((Recive_table[9]=='G')&&(Recive_table[10]=='P'))
{
if(Recive_table[15]=='0')
{
LED0=0; //红灯亮
ESP8266_Sent("1号灯开灯miandeng");
//wifi模块向pc端或手机端 发送"灯灭
}
else
if (Recive_table[15]=='1')
{
LED0=1; //红灯灭
ESP8266_Sent("1号灯关灯liangdeng");
//wifi模块向pc端或手机端 发送"灯亮"
}
else
if (Recive_table[15]=='2')
{
LED1=0; //绿灯亮
ESP8266_Sent("2号灯开灯miandeng");
}
else
if (Recive_table[15]=='3')
{
LED1=1; //绿灯灭
ESP8266_Sent("2号灯关灯miandeng");
}
else
if (Recive_table[15]=='4')
{
LED2=0; //黄灯亮
ESP8266_Sent("3号灯开灯miandeng");
}
else
if (Recive_table[15]=='5')
{
LED2=1; //黄灯灭
ESP8266_Sent("3号灯关灯miandeng");
}
}
}
}
}
/*********************************************************************
名称:串行通讯中断 作用:发送或接收结束后进入该函数,对相应的标志位软件清0,实现模块对数据正常的收发。
********************************************************************/
void Uart_Interrupt() interrupt 4
{
static uchar i=0;
if(RI==1)
{
RI=0;
Receive=SBUF; //MCU接收wifi模块反馈回来的数据
Recive_table[i]=Receive;
if((Recive_table[i]=='\n'))
{
i=0;
}
else i++; //遇到换行 重新装值
}
else TI=0;
}
-
单片机串口通信原理和控制程序
2017-06-17 16:35:15在实际应用中,往往串口还要和电脑上的上位机软件进行交互,实现电脑软件发送不同的指令,单片机对应执行不同操作的功能,这就要求我们组织一个比较合理的通信机制和逻辑关系,用来实现我们想要的结果。 本节所...我们前边学串口通信的时候,比较注重的是串口底层时序上的操作过程,所以例程都是简单的收发字符或者字符串。在实际应用中,往往串口还要和电脑上的上位机软件进行交互,实现电脑软件发送不同的指令,单片机对应执行不同操作的功能,这就要求我们组织一个比较合理的通信机制和逻辑关系,用来实现我们想要的结果。
本节所提供程序的功能是,通过电脑串口调试助手下发三个不同的命令,第一条指令:buzz on 可以让蜂鸣器响;第二条指令:buzz off 可以让蜂鸣器不响;第三条指令:showstr ,这个命令空格后边,可以添加任何字符串,让后边的字符串在 1602 液晶上显示出来,同时不管发送什么命令,单片机收到后把命令原封不动的再通过串口发送给电脑,以表示“我收到了„„你可以检查下对不对”。这样的感觉是不是更像是一个小项目了呢?
对于串口通信部分来说,单片机给电脑发字符串好说,有多大的数组,我们就发送多少个字节即可,但是单片机接收数据,接收多少个才应该是一帧完整的数据呢?数据接收起始头在哪里,结束在哪里?这些我们在接收到数据前都是无从得知的。那怎么办呢?
我们的编程思路基于这样一种通常的事实:当需要发送一帧(多个字节)数据时,这些数据都是连续不断的发送的,即发送完一个字节后会紧接着发送下一个字节,期间没有间隔或间隔很短,而当这一帧数据都发送完毕后,就会间隔很长一段时间(相对于连续发送时的间隔来讲)不再发送数据,也就是通信总线上会空闲一段较长的时间。于是我们就建立这样一种程序机制:设置一个软件的总线空闲定时器,这个定时器在有数据传输时(从单片机接收角度来说就是接收到数据时)清零,而在总线空闲时(也就是没有接收到数据时)时累加,当它累加到一定时间(例程里是 30ms)后,我们就可以认定一帧完整的数据已经传输完毕了,于是告诉其它程序可以来处理数据了,本次的数据处理完后就恢复到初始状态,再准备下一次的接收。那么这个用于判定一帧结束的空闲时间取多少合适呢?它取决于多个条件,并没有一个固定值,我们这里介绍几个需要考虑的原则:第一,这个时间必须大于波特率周期,很明显我们的单片机接收中断产生是在一个字节接收完毕后,也就是一个时刻点,而其接收过程我们的程序是无从知晓的,因此在至少一个波特率周期内你绝不能认为空闲已经时间达到了。第二,要考虑发送方的系统延时,因为不是所有的发送方都能让数据严格无间隔的发送,因为软件响应、关中断、系统临界区等等操作都会引起延时,所以还得再附加几个到十几个 ms 的时间。我们选取的 30ms 是一个折中的经验值,它能适应大部分的波特率(大于1200)和大部分的系统延时(PC 机或其它单片机系统)情况。
我先把这个程序最重要的 UART.c 文件中的程序贴出来,一点点给大家解析,这个是实际项目开发常用的用法,大家一定要认真弄明白。- /*****************************Uart.c 文件程序源代码*****************************/
- #include <reg52.h>
- bit flagFrame = 0; //帧接收完成标志,即接收到一帧新数据
- bit flagTxd = 0; //单字节发送完成标志,用来替代 TXD 中断标志位
- unsigned char cntRxd = 0; //接收字节计数器
- unsigned char pdata bufRxd[64]; //接收字节缓冲区
- extern void UartAction(unsigned char *buf, unsigned char len);
- /* 串口配置函数,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
- }
- /* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
- void UartWrite(unsigned char *buf, unsigned char len){
- while (len--){ //循环发送所有字节
- flagTxd = 0; //清零发送标志
- SBUF = *buf++; //发送一个字节数据
- while (!flagTxd); //等待该字节发送完成
- }
- }
- /* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
- unsigned char UartRead(unsigned char *buf, unsigned char len){
- unsigned char i;
- //指定读取长度大于实际接收到的数据长度时,
- //读取长度设置为实际接收到的数据长度
- if (len > cntRxd){
- len = cntRxd;
- }
- for (i=0; i<len; i++){ //拷贝接收到的数据到接收指针上
- *buf++ = bufRxd[i];
- }
- cntRxd = 0; //接收计数器清零
- return len; //返回实际读取长度
- }
- /* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
- void UartRxMonitor(unsigned char ms){
- static unsigned char cntbkp = 0;
- static unsigned char idletmr = 0;
- if (cntRxd > 0){ //接收计数器大于零时,监控总线空闲时间
- if (cntbkp != cntRxd){ //接收计数器改变,即刚接收到数据时,清零空闲计时
- cntbkp = cntRxd;
- idletmr = 0;
- }else{ //接收计数器未改变,即总线空闲时,累积空闲时间
- if (idletmr < 30){ //空闲计时小于 30ms 时,持续累加
- idletmr += ms;
- if (idletmr >= 30){ //空闲时间达到 30ms 时,即判定为一帧接收完毕
- flagFrame = 1; //设置帧接收完成标志
- }
- }
- }
- }else{
- cntbkp = 0;
- }
- }
- /* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
- void UartDriver(){
- unsigned char len;
- unsigned char pdata buf[40];
- if (flagFrame){ //有命令到达时,读取处理该命令
- flagFrame = 0;
- len = UartRead(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
- UartAction(buf, len); //传递数据帧,调用动作执行函数
- }
- }
- /* 串口中断服务函数 */
- void InterruptUART() interrupt 4{
- if (RI){ //接收到新字节
- RI = 0; //清零接收中断标志位
- //接收缓冲区尚未用完时,保存接收字节,并递增计数器
- if (cntRxd < sizeof(bufRxd)){{
- bufRxd[cntRxd++] = SBUF;
- }
- }
- if (TI){ //字节发送完毕
- TI = 0; //清零发送中断标志位
- flagTxd = 1; //设置字节发送完成标志
- }
- }
1、接收数据的处理,在串口中断中,将接收到的字节都存入缓冲区 bufRxd 中,同时利用另外的定时器中断通过间隔调用 UartRxMonitor 来监控一帧数据是否接收完毕,判定的原则就是我们前面介绍的空闲时间,当判定一帧数据结束完毕时,设置 flagFrame 标志,主循环中可以通过调用 UartDriver 来检测该标志,并处理接收到的数据。当要处理接收到的数据时,先通过串口读取函数 UartRead 把接收缓冲区 bufRxd 中的数据读取出来,然后再对读到的数据进行判断处理。也许你会说,既然数据都已经接收到 bufRxd 中了,那我直接在这里面用不就行了嘛,何必还得再拷贝到另一个地方去呢?我们设计这种双缓冲的机制,主要是为了提高串口接收到响应效率:首先如果你在 bufRxd 中处理数据,那么这时侯就不能再接收任何数据,因为新接收的数据会破坏原来的数据,造成其不完整和混乱;其次,这个处理过程可能会耗费较长的时间,比如说上位机现在就给你发来一个延时显示的命令,那么在这个延时的过程中你都无法去接收新的命令,在上位机看来就是你暂时失去响应了。而使用这种双缓冲机制就可以大大改善这个问题,因为数据拷贝所需的时间是相当短的,而只要拷贝出去后,bufRxd 就可以马上准备去接收新数据了。
2、串口数据写入函数 UartWrite,它把数据指针 buf 指向的数据块连续的由串口发送出去。虽然我们的串口程序启用了中断,但这里的发送功能却没有在中断中完成,而是仍然靠查询发送中断标志 flagTxd(因中断函数内必须清零 TI,否则中断会重复进入执行,所以另置了一个 flagTxd 来代替 TI)来完成,当然也可以采用先把发送数据拷贝到一个缓冲区中,然后再在中断中发缓冲区数据发送出去的方式,但这样一是要耗费额外的内存,二是使程序更复杂。这里也还是想告诉大家,简单方式可以解决的问题就不要搞得更复杂。- /*****************************main.c 文件程序源代码******************************/
- #include <reg52.h>
- sbit BUZZ = P1^6; //蜂鸣器控制引脚
- bit flagBuzzOn = 0; //蜂鸣器启动标志
- unsigned char T0RH = 0; //T0 重载值的高字节
- unsigned char T0RL = 0; //T0 重载值的低字节
- void ConfigTimer0(unsigned int ms);
- extern void UartDriver();
- extern void ConfigUART(unsigned int baud);
- extern void UartRxMonitor(unsigned char ms);
- extern void UartWrite(unsigned char *buf, unsigned char len);
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
- void main(){
- EA = 1; //开总中断
- ConfigTimer0(1); //配置 T0 定时 1ms
- ConfigUART(9600); //配置波特率为 9600
- InitLcd1602(); //初始化液晶
- while (1){
- UartDriver(); //调用串口驱动
- }
- }
- /* 内存比较函数,比较两个指针所指向的内存数据是否相同,
- ptr1-待比较指针 1,ptr2-待比较指针 2,len-待比较长度
- 返回值-两段内存数据完全相同时返回 1,不同返回 0 */
- bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len){
- while (len--){
- if (*ptr1++ != *ptr2++){ //遇到不相等数据时即刻返回 0
- return 0;
- }
- }
- return 1; //比较完全部长度数据都相等则返回 1
- }
- /* 串口动作函数,根据接收到的命令帧执行响应的动作
- buf-接收到的命令帧指针,len-命令帧长度 */
- void UartAction(unsigned char *buf, unsigned char len){
- unsigned char i;
- unsigned char code cmd0[] = "buzz on"; //开蜂鸣器命令
- unsigned char code cmd1[] = "buzz off"; //关蜂鸣器命令
- unsigned char code cmd2[] = "showstr "; //字符串显示命令
- unsigned char code cmdLen[] = { //命令长度汇总表
- sizeof(cmd0)-1, sizeof(cmd1)-1, sizeof(cmd2)-1,
- };
- unsigned char code *cmdPtr[] = { //命令指针汇总表
- &cmd0[0], &cmd1[0], &cmd2[0],
- };
- for (i=0; i<sizeof(cmdLen); i++){ //遍历命令列表,查找相同命令
- if (len >= cmdLen[i]){ //首先接收到的数据长度要不小于命令长度
- if (CmpMemory(buf, cmdPtr[i], cmdLen[i])){ //比较相同时退出循环
- break;
- }
- }
- }
- switch (i){ //循环退出时 i 的值即是当前命令的索引值
- case 0:
- flagBuzzOn = 1; //开启蜂鸣器
- break;
- case 1:
- flagBuzzOn = 0; //关闭蜂鸣器
- break;
- case 2:
- buf[len] = '\0'; //为接收到的字符串添加结束符
- LcdShowStr(0, 0, buf+cmdLen[2]); //显示命令后的字符串
- i = len - cmdLen[2]; //计算有效字符个数
- if (i < 16){ //有效字符少于 16 时,清除液晶上的后续字符位
- LcdAreaClear(i, 0, 16-i);
- }
- break;
- default: //未找到相符命令时,给上机发送“错误命令”的提示
- UartWrite("bad command.\r\n", sizeof("bad command.\r\n")-1);
- return;
- }
- buf[len++] = '\r'; //有效命令被执行后,在原命令帧之后添加
- buf[len++] = '\n'; //回车换行符后返回给上位机,表示已执行
- UartWrite(buf, len);
- }
- /* 配置并启动 T0,ms-T0 定时时间 */
- void ConfigTimer0(unsigned int ms){
- unsigned long tmp; //临时变量
- tmp = 11059200 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- tmp = tmp + 33; //补偿中断响应延时造成的误差
- T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0; //清零 T0 的控制位
- TMOD |= 0x01; //配置 T0 为模式 1
- TH0 = T0RH; //加载 T0 重载值
- TL0 = T0RL;
- ET0 = 1; //使能 T0 中断
- TR0 = 1; //启动 T0
- }
- /* T0 中断服务函数,执行串口接收监控和蜂鸣器驱动 */
- void InterruptTimer0() interrupt 1{
- TH0 = T0RH; //重新加载重载值
- TL0 = T0RL;
- if (flagBuzzOn){ //执行蜂鸣器鸣叫或关闭
- BUZZ = ~BUZZ;
- }else{
- BUZZ = 1;
- }
- UartRxMonitor(1); //串口接收监控
- }
首先来看 CmpMemory 函数,这个函数很简单,就是比较两段内存数据,通常都是数组中的数据,函数接收两段数据的指针,然后逐个字节比较——if (*ptr1++ != *ptr2++),这行代码既完成了两个指针指向的数据的比较,又在比较完后把两个指针都各自+1,从这里是不是也能领略到一点 C 语言的简洁高效的魅力呢。这个函数的用处自然就是用来比较我们接收到的数据和事先放在程序里的命令字符串是否相同,从而找出相符的命令了。
接下来是 UartAction 函数对接收数据的解析和处理方法,先把接收的数据与所支持的命令字符串逐条比较,这个比较中首先要确保接收的长度大于命令字符串的长度,然后再用上述的 CmpMemory 函数逐字节比较,如果比较相同就立即退出循环,不同则继续对比下一条命令。当找到相符的命令字符串时,最终 i 的值就是该命令在其列表中的索引位置,当遍历完命令列表都没有找到相符的命令时,最终 i 的值将等于命令总数,那么接下来就用 switch语句根据 i 的值来执行具体的动作,这个就不需要再详细说明了。- /***************************Lcd1602.c 文件程序源代码*****************************/
- #include <reg52.h>
- #define LCD1602_DB P0
- sbit LCD1602_RS = P1^0;
- sbit LCD1602_RW = P1^1;
- sbit LCD1602_E = P1^5;
- /* 等待液晶准备好 */
- void LcdWaitReady(){
- unsigned char sta;
- LCD1602_DB = 0xFF;
- LCD1602_RS = 0;
- LCD1602_RW = 1;
- do {
- LCD1602_E = 1;
- sta = LCD1602_DB; //读取状态字
- LCD1602_E = 0;
- } while (sta & 0x80); //bit7 等于 1 表示液晶正忙,重复检测直到其等于 0 为止
- }
- /* 向 LCD1602 液晶写入一字节命令,cmd-待写入命令值 */
- void LcdWriteCmd(unsigned char cmd){
- LcdWaitReady();
- LCD1602_RS = 0;
- LCD1602_RW = 0;
- LCD1602_DB = cmd;
- LCD1602_E = 1;
- LCD1602_E = 0;
- }
- /* 向 LCD1602 液晶写入一字节数据,dat-待写入数据值 */
- void LcdWriteDat(unsigned char dat){
- LcdWaitReady();
- LCD1602_RS = 1;
- LCD1602_RW = 0;
- LCD1602_DB = dat;
- LCD1602_E = 1;
- LCD1602_E = 0;
- }
- /* 设置显示 RAM 起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
- void LcdSetCursor(unsigned char x, unsigned char y){
- unsigned char addr;
- if (y == 0){ //由输入的屏幕坐标计算显示 RAM 的地址
- addr = 0x00 + x; //第一行字符地址从 0x00 起始
- }else{
- addr = 0x40 + x; //第二行字符地址从 0x40 起始
- }
- LcdWriteCmd(addr | 0x80); //设置 RAM 地址
- }
- /* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
- void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str){
- LcdSetCursor(x, y); //设置起始地址
- while (*str != '\0'){ //连续写入字符串数据,直到检测到结束符
- LcdWriteDat(*str++);
- }
- }
- /* 区域清除,清除从(x,y)坐标起始的 len 个字符位 */
- void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len){
- LcdSetCursor(x, y); //设置起始地址
- while (len--){ //连续写入空格
- LcdWriteDat(' ');
- }
- }
- /* 初始化 1602 液晶 */
- void InitLcd1602(){
- LcdWriteCmd(0x38); //16*2 显示,5*7 点阵,8 位数据接口
- LcdWriteCmd(0x0C); //显示器开,光标关闭
- LcdWriteCmd(0x06); //文字不动,地址自动+1
- LcdWriteCmd(0x01); //清屏
- }
经过这几个多文件工程的练习后,大家是否发现,在采用多文件模块化编程后,不光是某些函数,甚至整个 c 文件,如有需要,我们都可以直接复制到其它的新工程中使用,非常方便功能程序的移植,这样随着实践积累的增加,你会发现工作效率变得越来越高了。 -
单片机串口通信调试心得
2018-09-13 18:08:433.奇偶校验,看一下通信奇偶校对不对,当初调试的时候,电脑给两块板 发的时候都是可以的,两个互相不能通信,简直无法理解。 后来发现,随便设置奇偶校验,电脑的串口助手都不会乱码。 嗨,实在不行,可以换一个...1.tx,rx是否插反
2.波特率设置。这个是跟晶振有关的,看一下程序的跟实际的是否一样。
3.奇偶校验,看一下通信奇偶校对不对,当初调试的时候,电脑给两块板
发的时候都是可以的,两个互相不能通信,简直无法理解。
后来发现,随便设置奇偶校验,电脑的串口助手都不会乱码。
嗨,实在不行,可以换一个串口软件,遇到过两次,是软件的问题。
自己遇到的,帮别人解决的就记得这些了,
有想起来再补充吧
-
如何实现单片机与PC之间的通信
2015-04-04 05:47:48想用opencv编写识别程序,与atmega128通讯,来控制机械臂抓取物体 用一根USB串口转接线连接单片机和笔记本电脑 怎么实现通讯(单独编程?还是可以安装什么软件?) 求大神们帮帮忙~万分感谢 -
手机与单片机之间蓝牙串口通信(1)
2018-05-02 22:11:29工具包括淘宝上淘的stc单片机实验板一块,hc-06蓝牙模块一个,杜邦线,win7电脑一部,安卓手机一部,相关软件:单片机小精灵,串口通讯助手,keil以及单片机烧录软件,蓝牙通讯软件APP。软件基本上都是免安装直接...打算利用蓝牙芯片HC06实现手机和单片机之间的简单通信。工具包括淘宝上淘的stc单片机实验板一块,hc-06蓝牙模块一个,杜邦线,win7电脑一部,安卓手机一部,相关软件:单片机小精灵,串口通讯助手,keil以及单片机烧录软件,蓝牙通讯软件APP。软件基本上都是免安装直接运行的。
工作流程简单总结下为以下3步:1.利用单片机小精灵软件,做好烧录程序,确定波特率应该设置为24002.hc-06蓝牙模块进入AT模式,串口通讯助手成功将蓝牙模块波特率设置为24003.将烧录程序通过keil编译成功后烧录至单片机实验板上,手机上安装好APP,设置完成后运行,确定成功。步骤(2)见https://blog.csdn.net/dok12/article/details/80152239步骤(3)见https://blog.csdn.net/dok12/article/details/801730本篇先介绍步骤1。工具,单片机小精灵软件,免安装,直接运行。打开单片机小精灵软件,选择串口波特率选项。必须选择好晶振和波特率。其他选项,c语言还是汇编,是否串口中断,波特率加倍,允许接收都自己决定。因为淘宝买到的单片机实验板是12M晶振,蓝牙模块的默认波特率是9600。所以一开始输入这两项数据。结果发现误差太大,必须修改。晶振改不了,只好改波特率了。修改波特率为2400后误差控制在千分之一点六,效果不错,得到了一个C语言的串口通信基本框架了。根据这个框架做了个C语言程序,目标是对单片机实现蓝牙通讯,实现不同的单片机流水灯效果,并且得到回复数字8。#include <reg51.h> unsigned char k; void InitUART(void) { TMOD = 0x20; SCON = 0x50; TH1 = 0xF3; TL1 = 0xF3; PCON = 0x00; EA = 1; ES = 1; TR1 = 1; } /*******延时函数*************/ void delay(unsigned int i) { unsigned char j; for(i; i > 0; i--) for(j = 255; j > 0; j--); } void main(void) { k=0; InitUART(); while (1){ if(k==1) {P1=0xff;delay(500);P1=0x00;delay(500);} else if (k==2) {P1=0x01;delay(500);P1=0xfe;delay(500);} else {P1=0x02;delay(500);P1=0xfd;delay(500);} } } void SendOneByte(unsigned char c) { SBUF = c; while(!TI); TI = 0; } void UARTInterrupt(void) interrupt 4 { if(RI) { RI = 0; //add your code here! k++; if(k>2)k=0; SendOneByte(8); } else TI = 0; }
-
单片机ISP下载软件串口助手的hex模式和文本模式的区别
2020-07-22 13:37:15首先hex模式是十六进制模式,当我们用电脑以hex模式给...注意:蓝牙模块或者WiFi模块和单片机通信也是一样的。 下面有一篇C51的的程序,大家可以试试! # include <reg52.h> sbit LED = P2^0; # define fosc 1 -
[置顶] 单片机串口通信原理和控制程序
2017-06-17 16:35:00在实际应用中,往往串口还要和电脑上的上位机软件进行交互,实现电脑软件发送不同的指令,单片机对应执行不同操作的功能,这就要求我们组织一个比较合理的通信机制和逻辑关系,用来实现我们想要的结果。 本节所提供... -
用单片机串口和modbus poll 进行通信
2018-11-30 18:20:18之前为了调通串口,所以用的是单片机的串口和串口助手进行的通信,为了更方便的模拟主机modbus,我决定采用软件modbus poll. modbus poll 和 mosbud slave 可以配套使用,在同一台电脑运行的时候,需要使用虚拟串口... -
手机与单片机之间蓝牙串口通信(2)
2018-05-02 22:17:24首先将HC-06蓝牙通信模块和单片机串口通过杜邦线连接,接线如图所示:RX-P30 TX-P31tips:淘宝购买HC06模块的时候,卖家表示蓝牙模块的TX,RX端的丝印搞反了,所以如果你发现蓝牙模块无法和单片机通信的话,可以尝试... -
USB转ESP8266 01 WIFI串口模块 电脑无线通信单片机转接板烧录固件 AirKiss SmartConfig 智能配网
2020-04-19 14:42:36ESP8266 01/01SUSB串口转接板,用于跟WIFI调试软件工具通信,还可以烧录固件。 转接板图: 直接使用CH340G串口驱动,可以使用官方esp8266 调试工具发送指令进行设置。 烧写固件的时候把短接冒插上,正常使用... -
51单片机模拟实现SPI完成串口通信
2020-03-24 16:47:04本文我们拟使用两个51单片机软件模拟实现SPI完成通信,相互接收和发送数据。即在A电脑上发送字符,B电脑上接收到字符,反之相同。 MODE1: CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也... -
虚拟串口VSP6.0(RS-232串口虚拟可完成串口通信软件间的纯软件调试)
2009-12-11 08:55:05一个Windows系统下的虚拟...如果你要在一台电脑上调试两个需要通过串口通信的软件,它就是最佳选择,有了它,可以让你需要任何的硬件连接就完成两个串口通信软件的调试,在单片机系统上、下位机通信仿真中尤其好用! -
蓝桥杯单片机第十三篇_串口通信
2020-07-31 20:51:18上位机就是电脑操作方,下位机就是接收方,也就是单片机,当接受到电脑给的数据,识别后作出想要的操作 #include <stc15.h> unsigned char buf[12]; unsigned char num=0; void UartInit(void) //9600bps@... -
单片机与DSP中的基于μPD78F0034单片机的出租车计费器的设计与实现
2020-12-10 10:13:02摘要:介绍了基于μPD78F0034单片机和模块式结构的出租车计费器的硬件和软件设计方法,讨论了μPD78F0034单片机的主要特点;介绍了该单片机和PC机串行通信的硬件连接方法;同时给出了采用单、双信号防作弊技术来防止... -
4路定时开关USB通信单片机控制器JMDM-RTC4MR.rar
2019-09-21 21:47:394路定时开关USB通信单片机控制器JMDM-RTC4MRrar,一、简介JMDM-RTC4MR是深圳市精敏数字机器有限公司自主研发的一款具有实时时钟定时,电池电压自动检测和自动充电,可实现4路继电器联机或脱机控制,高可靠稳定性的工业... -
嵌入式系统/ARM技术中的采用Cortex-M3单片机设计的WiFi物联网小车
2020-10-19 19:31:03与传统的“智能小车”相比,主要特点在于使用32 位高性能单片机控制、互联网通信机制和电脑上位机软件控制。此方案融合了电脑软件、网络通信、图像处理、图形显示、运动控制、速度采集和温度采集等技术,具有... -
采用Cortex-M3单片机设计的WiFi物联网小车
2020-08-21 00:44:09WiFi物联网小车设计方案,采用电脑上位机软件通过无线WiFi 控制小车的运动,采集小车的信息。与传统的“智能小车”相比,主要特点在于使用32 位高性能单片机控制、互联网通信机制和电脑上位机软件控制。 -
【软件工程师学硬件】之 通信
2019-06-12 09:27:56提到通信,软件工程师并不陌生,但他们更多的是指网络通信,尤其是指socket。...硬件虽然属于底层,但是通信也是少不了的,比如说,单片机要和电脑交换数据、单片机之间交换数据、单片机和传感器之间的数据交换以及... -
基于单片机的IPTV机顶盒的设计
2020-10-18 07:45:40IPTV是利用宽带网基础设施,以家用电视机(或...另外一类机顶盒内部包含操作系统和互联网浏览软件,通过电话网或有线电视网连接互联网,使用电视机作为显示器,从而实现没有电脑的上网,这种机顶盒叫做网络机顶盒,本 -
51单片机串口通讯的实现.
2018-05-07 16:54:49在串口通讯实际操作里面往往串口还要和电脑上的上位机软件进行交互,实现电脑软件发送不同的指令,单片机对应执行不同操作的功能,这就要求我们组织一个比较合理的通信机制和逻辑关系,用来实现我们想要的结果。... -
单片机与DSP中的基于AT89C51的激光密码锁的设计
2020-12-13 15:32:26电脑密码控制器是以微处理器和数字存储器为代表,采用了当今高新科技、最新优化软件设 计而成,所追求的高保密性、高可靠性和广泛的适用性,特别是在区域管理和集中控制防盗 中显示出诸多优势,是一种现在比较流行... -
51单片机当键盘与PC的PS 2程序和PS 2接口协议设计PDF及键盘测试软件(修正).rar
2010-09-04 10:32:12该份程序包含写PS 2通信所需要的协议文件(个人从多份文档里筛选出来的),以及键盘接收软件,和个人写出来的程序(只需要最小系统经过一条PS/2线和电脑连接就可以实现发码,通过附带的键盘接收软件可以收到)。... -
单片机串口通讯
2017-07-31 15:22:001、需求:实现电脑端控制单片机打开灯光风扇,...然后确定我们单片机的晶振,我是用的是11.0592M的【即9600】,差不多我们就可以开始我们的开发了 5、我们默认不定义复杂的通信协议 我们先来开发我们的单片机程序... -
使用ESP8266和51单片机的智能开关/智能灯
2017-03-29 11:04:54本文章所介绍的智能开关为在局域网内实现手机开关的简单方法,功能能简单,仅供参考。 如果对ESP8266模块不了解...TCP通信调试:Python3二、硬件电路连接ESP8266的最小系统参照:ESP8266与电脑连接 ESP8266最小系统与 -
单片机与DSP中的射频卡多协议读写器的设计和实现
2020-10-23 11:27:31据业内人士预测,RFID技术市场将在未来五年内在新的产品与服务上带来30至100亿美金的商机,随之而来的还有服务器、资料储存系统、资料库程序、商业管理软件、顾问服务,以及其他电脑基础建设的庞大需求。或许这些... -
使用虚拟串口软件实现单机进行串口通信调试
2007-04-20 21:55:00串口已经从很多人的电脑里消失,但是串口在嵌入式系统开发中依然扮演着不不可或缺的角色,在虚拟化的今天,很多硬件的东西都能虚拟出来,串口当然也不例外,利用虚拟串口软件,可以在没有串口的电脑上虚拟出一对甚至... -
单片机教程-(第2版)单片机原理与应用系统设计实用教程
2015-11-09 16:35:24这些单元突出了单片机的控制特性,使得单片机的功能越来越强大,应用越来越广泛。 单片机最早是被用在工业控制领域。从Intel公司于1971年生产的第一片单片机Intel-4004开始,单片机就开创了电子应用的智能化新时代。... -
初学单片机,学完了串口部分,有一些自己的思考,请大神解答一下,感激不尽
2016-10-12 06:05:094.我理解单片机通信的意义,是不是一块单片机资源不够用,所以用两块,或者两块以上,只进行数据通讯,这样就可以减轻一块单片机的负担,还有什么其他意义吗?刚学这个部分,所以请大神们别笑我乱想。![图片]...
-
(新)备战2021软考网络工程师分类强化培训套餐
-
01 周斌-Cuda编程.zip
-
css子元素如何相对父元素定位?
-
T+V15专属云高发问题处理
-
T+V15专属云工序管理计件工资
-
PHP7 VS2015编译(扩展开发)
-
数字信号处理课程设计.pdf
-
信号的采样及采样定理.pdf
-
08 Python编程语言基础技术框架(4)之函数介绍.mp4
-
第3章 入门程序、常量、变量
-
寻找主要元素.pdf
-
otp_win64_23.2.exe
-
数量性状基因定位研究中若干常见问题的分析与解答.pdf
-
基于SEIR模型的新冠肺炎预测
-
三维地图GIS大数据可视化
-
02 Python编程语言初接触.mp4
-
史上最全!北大青鸟java学士后第二单元超市账单管理系统(包含oracle数据库创建的SQL代码)只要配置好JNDI就可以运行
-
屏幕颜色拾取器.zip
-
计算机病毒分为哪三类
-
Go开发第一个小程序——解压 5291