Proteus平台下基于Arduino的UART串口通信系统仿真及传感器数据采集与LCD屏幕二级菜单功能实现(附工程源码、设计报告)

若需要运行源码,需要将控制温湿度传感器以及LCD屏幕(TFTv2.h DHT.h)的头文件添加进工程

主程序初始化

#include <stdint.h>
#include "TFTv2.h"
#include <SPI.h>
#include <DHT.h>
#define DHTPIN 8     // 温湿度传感器连接的引脚
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE,4);
char sensorPrintout[4];//存储
int count=0;
const int interruptA = 3;// 设置中断Interrupt引脚
const int interruptB = 2;
const int interruptD = 19;
int F[2] = {0,0};//初始化页面状态参量
int S[2] = {0,0};//初始化页面参量
int R = -1;//页面索引参量
int button1 = 3;//管脚号定义,下同
int button2 = 2;
int button4 = 19;
//LED 代码初始化部分
const int ledPin = 13; // led连接的引脚
int ledState = LOW; // led状态,亮或者灭,可以修改 
long previousMillis = 0; // 存储最后一次的led状态
// 这里使用了长整型变量,因为使用了ms,瞬间的数值变化非常大。 
long interval = 500; // 间隔闪烁的时间长度 
unsigned long time_find = 0;

void setup() 
{ 
 Serial.begin(9600); //串口初始化
 Serial2.begin(9600);//串口初始化
 dht.begin();
 /*  LCD 初始化  */ 
 SPSR |= (1 << SPI2X);                       // 2x SPI speed 
 TFT_BL_ON;                                  // turn on the background light
 Tft.TFTinit();                              //init TFT library
 Tft.drawLine(0,0,239,319,RED);              //start: (0, 0) end: (239, 319), color : RED
 Tft.drawVerticalLine(60,100,100,GREEN);     // Draw a vertical line
                                               // start: (60, 100) length: 100 color: green
 Tft.drawHorizontalLine(30,60,150,BLUE);     //Draw a horizontal line
                                               //start: (30, 60), high: 150, color: blue
 Tft.drawCircle(100, 100, 30,YELLOW);        //center: (100, 100), r = 30 ,color : YELLOW   
 Tft.drawCircle(100, 200, 40,CYAN);          // center: (100, 200), r = 10 ,color : CYAN  
 Tft.fillCircle(200, 100, 30,RED);           //center: (200, 100), r = 30 ,color : RED    
 Tft.fillCircle(200, 200, 30,BLUE);          //center: (200, 200), r = 30 ,color : BLUE     
 Tft.drawString("Hello",0,180,3,CYAN);       // draw string: "hello", (0, 180), size: 3, color: CYAN
 Tft.drawString("World!!",60,220,4,WHITE);    // draw string: "world!!", (80, 230), size: 4, color: WHITE
 delay(500);
/*  LCD 初始化结束  */
 pinMode(button1, INPUT); //管脚输入输出方式
 pinMode(button2, INPUT);
 pinMode(button4, INPUT);
 pinMode(ledPin, OUTPUT); 
 digitalWrite(button1, HIGH);//数字写为高电平
 digitalWrite(button2, HIGH);
 digitalWrite(button4, HIGH); 
 attachInterrupt(digitalPinToInterrupt(interruptA), Choose1, FALLING);//中断下降沿触发
 attachInterrupt(digitalPinToInterrupt(interruptB), Choose2, FALLING);
 attachInterrupt(digitalPinToInterrupt(interruptD), Return_, FALLING);
} 

部分运行效果(完整工程在资源里)

二级菜单

三个按键控制菜单,功能分别为:选择功能1,选择功能2,以及返回上一级;

通过三个外部中断对页面状态参量进行控制:

void Choose1(){//确认选择第一个功能
R = R+1;//对状态参量进行操作,进入下一页,即F数组加一位
F[R] = F[R]+1;
}

void Choose2(){//确认选择第二个功能
R = R+1;//对状态参量进行操作,进入下一页,即S数组加一位
S[R] = S[R]+1;
}

void Return_(){//返回上一级
if(F[R] == 1){//将状态参量退回到上一级
F[R] = F[R]-1;}
else if(S[R] == 1){
S[R] = S[R]-1;}
R = R-1;
}

温湿度传感器

while(F[0] == 1 & F[1] ==0 & S[0] == 0 & S[1] == 1){//进入温湿度传感器界面
 float h = dht.readHumidity();// 读温度湿度的取值
  // Read temperature as Celsius
 float t = dht.readTemperature();
  // Read temperature as Fahrenheit
 float f = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
 float hi = dht.computeHeatIndex(f, h);
 Tft.fillScreen();                               //清屏
 Tft.drawString("Humidity: ",0,0,2,CYAN);       // 可修改坐标 大小 颜色等
 Tft.drawFloat(h,3,60,50,1,WHITE);
 Tft.drawString("Temperature: ",0,100,2,CYAN);
 Tft.drawFloat(t,3,60,150,1,WHITE);
 Tft.drawString("Heat index:",0,200,2,CYAN);
 Tft.drawFloat(hi,3,60,250,1,WHITE);
 delay(500);}

可靠通信(停止等待协议)

停止等待

当U1收到U2的ACK后才会发送下一次传感器采集到的数据

超时重传

当关闭U2后,U1到达设定的超时时间后,进行重传操作,直到收到U2的确认收到的信息

while(F[0] == 1 & F[1] == 1 & S[0] == 0 & S[1] == 0){//进入光敏传感器功能,同时进行串口可靠通信
 String sensorVal = String(analogRead(A0));//读取模拟值

 if(Serial2.find("ack")){//若收到接收端的ack确认信息
 time_find = millis();//记录更新最近一次收到确认的时间信息
 Serial2.print(sensorVal);
 Tft.fillScreen();
 Tft.drawString("Data Transmitted!",0,0,2,CYAN);//收到确认后,显示可视化信息,再发送下一次数据
 delay(125);
 }
  
 unsigned long time_now = millis();//读取现在时钟信息
  
 if(time_now - time_find > 3000){//设置超时时间3秒
 Serial2.print(sensorVal);//3秒后再发送一次
 Tft.fillScreen();
 Tft.drawString("Timeout!",50,0,2,CYAN);//显示超时可视化信息
 time_find = time_now;//存储最新一次执行超时重传的时间实现重新计时
 delay(125);}
 
 sensorVal.toCharArray(sensorPrintout, 4);//U1 LCD显示出现在传感器的值
 Tft.fillScreen();
 Tft.drawString("Sensor Data :",0,0,2,CYAN);//显示字符
 Tft.drawString(sensorPrintout,0,100,2,CYAN);
 delay(125);
 }

对于U1来说,只有收到ack确认后才发送下一次的数据,不然就会超时重传。设置变量time_now = millis() 来记录当前运行的总时间,这个变量主程序每循环一次就会更新一次。然后设置变量time_find = millis() (time_find初始化为0)来记录最新一次收到接收端发来的ack并传输数据的时间点。在主程序中每运行一次就会比较time_now – time_find 是否大于超时时间interval,本工程中设置超时时间为3秒,若大于超时时间则重传并LCD显示“Timeout!”,并将此时的time_now赋给time_find来存储最新一次执行超时重传的时间实现重新计时。

char sensorPrintout1[4];
void setup()
 { 
   Serial.begin(9600); 
   Serial1.begin(9600);
   //Serial.setTimeout(2000);
   Serial.print("ack");
 }

void loop()
 { 
   if(Serial.available()>0){
   Serial.readBytes(sensorPrintout1,4);
   Serial1.println(sensorPrintout1);
   Serial.print("ack");
   }
 }

当U2收到U1发来的数据时,使用readBytes函数读取U1通过串口发来的字符串数据,并存储到sensorPrintout1数组中,并将此数据通过串口1打印出来,通过连接的虚拟终端显示。同时通过串口向U1发送“ack”确认字段,并等待下一次数据的到来。

如有任何疑问可以留言

声明:只用作分享学习,共同进步,其他不做任何用途

物联沃分享整理
物联沃-IOTWORD物联网 » Proteus平台下基于Arduino的UART串口通信系统仿真及传感器数据采集与LCD屏幕二级菜单功能实现(附工程源码、设计报告)

发表评论