通过引用传递变量以避免全局变量和外部变量



我已经编写了程序,但它完全依赖于全局变量和外部变量的使用。我决定修复我的代码,并使其尽可能简单。然而,它似乎正朝着错误的方向发展。我有三种结构,在我的代码中几乎无处不在:

  1. 项目_侧面_结构
  2. 设备信息
  3. encoder_struct

我已经为tft显示编写了一个包装器。tft显示器必须知道3个结构的所有状态,因为它在屏幕上显示所有内容。因此,我将这些结构作为引用传递给我的tft函数。但是,由于tft函数是在代码的其他地方调用的(它可以是main.c,甚至可以在其他源文件中调用),因此必须将结构传递给调用tft方法的其他函数。

例如:我写了sensor.c和sensor.h。它包含了所有的传感器功能。在读取传感器后,根据传感器结果,它可能需要更新tft显示,因此我必须将所有结构数据传递给执行读取传感器的功能,即使该功能本身除了ftf更新功能之外并不关心这3个结构。我的传感器。c:

void Read_sensor_no_delay(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
if(sensor_disable == 0){
if(strncmp(item_inside->state, "PILDYMAS", 8) != 0)
{
sensor = digitalRead(SENSOR);
if(sensor==LOW  && sensor_prev_state==HIGH)// SENSOR ON
{
sensor_prev_state=LOW; // set the previous state to LOW
if (strncmp(item_inside->state,"ACTIVE",6)!=0){ // IF NUMBER TO PICK ITEMS IS 0, SET RED LIGHT TO SHOW OPERATOR WRONG BOX
handle_wrong_box(item_inside,device,encoder);
}

}
else if(sensor==HIGH && sensor_prev_state==LOW) //SENSOR DEACTIVATED
{ 
if(item_inside->num_to_pick > 0 && (strncmp(item_inside->state,"ACTIVE",6)==0) )// if number_to_pick >0, and device is activated, take items  
{ 
handle_active_device(item_inside,device,encoder);
sensor_disable = 1;
lastMsg2 = millis();
}   
else if(strncmp(item_inside->state,"ACTIVE",6)!=0)
{
handle_not_active_device(item_inside,device,encoder);
}
sensor_prev_state = HIGH;
}
}
}

else{
if (now - lastMsg2 > 4000) 
{
//Serial.println("5 seconds passed");
sensor_disable=0;
}
}

}



void handle_wrong_box(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
turn_ON_timer();
LED_strip_ON(red,PixelCount);     
update_screen_colour(ST77XX_RED,item_inside,device,encoder);
}


void handle_active_device(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){

sensor_prev_state = HIGH;         
item_inside->num_to_pick--;
item_inside->quantity--;
mb.Hreg(MAIN_REG, 12);    //PUT 55 IN REG1
mb.Hreg(NUMBER_TO_PICK_REG, item_inside->quantity);    // register 24
update_screen_colour(ST77XX_BLACK,item_inside,device,encoder); 
strcpy(item_inside->state,"DONE");
turn_ON_timer2();
if(item_inside->quantity <=10)
{
}
return;
}

void handle_not_active_device(item_inside_struct* item_inside, device_info* device, encoder_struct* encoder){
turn_OFF_timer();
LED_strip_ON(black,PixelCount);  
update_screen_colour(ST77XX_BLACK,item_inside,device,encoder);
sensor_prev_state = HIGH;
}

注意,read_sensor_no_delay()函数只需要知道item_inside_struct,而不关心device_info或encoder_struct,但我仍然必须将它们传递给函数。在read_sensor_no_delay()函数中,另一个函数被称为handle_wrong_box()。此函数将重新绘制显示并显示新数据,因此它必须知道所有3个结构。

我的tft.c:


#include "tft_custom.h"

int screen_colour = ST77XX_BLACK ;
int local_quantity = 0;
int local_number_to_pick = 0;
char local_eeprom_serial[10]="NONE";
char local_current_status[20] = "NONE";
int local_displaycounter = 0;
char local_device_id[10] = "NONE";
char local_device_version[10] = "NONE";
char local_mqtt_server[20] = "NONE";
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);


void TFT_setup(){
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.fillScreen(ST77XX_BLACK);
}

void TFT_display_update(item_inside_struct* item_inside,device_info* device, encoder_struct* encoder){    
tft.setTextSize(4); 
if(local_quantity != item_inside->quantity)
{
tft.setCursor(0, 0);
tft.fillRect(0,0, 80, 32, screen_colour);
local_quantity = item_inside->quantity;
tft.print(local_quantity);   //quantity inside          

}

if(local_number_to_pick != item_inside->num_to_pick)
{
tft.setCursor(0,32);  
tft.fillRect(0,32, 40, 32, screen_colour); 
local_number_to_pick = item_inside->num_to_pick;               
tft.print(local_number_to_pick);        // number2 means number to_pick
}

tft.setTextSize(1); 
if(strcmp(local_device_version,device->device_version)!= 0)
{
tft.setCursor(120,0);  
tft.fillRect(120,0, 10, 10, screen_colour);
strcpy(local_device_version,device->device_version);          
tft.print(local_device_version);        // number2 means number to_pick
}

if(strcmp(local_mqtt_server,device->mqtt_server)!= 0)
{
tft.setCursor(80,10);  
tft.fillRect(80,10, 40, 5, screen_colour);                
strcpy(local_mqtt_server,device->mqtt_server);
tft.print(local_mqtt_server);        // number2 means number to_pick
}

tft.setTextSize(2);
if(strcmp(local_device_id,device->DEVICE_ID)!= 0){ 
tft.setCursor(40,60);
tft.fillRect(40,60, 50, 16, screen_colour);    
strcpy(local_device_id,device->DEVICE_ID);
tft.print(local_device_id); 

}     

if(strcmp(local_current_status,item_inside->state)!= 0){ 
tft.setCursor(40,32);
tft.fillRect(40,32, 120, 16, screen_colour);  
strcpy(local_current_status,item_inside->state);
tft.print(local_current_status); 
}  

if(strcmp(local_eeprom_serial,item_inside->serial) !=0)
{
tft.setCursor(40,76);
tft.fillRect(40,76, 120, 16, screen_colour);  
strcpy(local_eeprom_serial, item_inside->serial);
tft.print(local_eeprom_serial);      //print SERIAL id

}

if(local_displaycounter != encoder->displaycounter)
{
tft.setCursor(40,94); 
tft.fillRect(40,94, 60, 16, screen_colour);   
local_displaycounter = encoder->displaycounter;
tft.print(local_displaycounter/10);      //print SERIAL id
}

}
void TFT_display(item_inside_struct* item_inside,device_info* device, encoder_struct* encoder){   
//tft.fillRect(0,0, 160, 80, ST77XX_BLACK);  
tft.setTextSize(4); 
tft.setCursor(0, 0);    
tft.print(item_inside->quantity);   //quantity inside          
tft.setCursor(0,32);                  
tft.print(item_inside->num_to_pick);        // number2 means number to_pick
tft.setTextSize(1); 
tft.setCursor(120,0);
tft.print(device->device_version);

tft.setCursor(80,10);             
tft.print(device->mqtt_server);        // number2 means number to_pick

tft.setTextSize(2); 
tft.setCursor(64,32);
tft.print(item_inside->state);        
tft.setCursor(40,60); 
tft.print(device->DEVICE_ID);        
tft.setCursor(40,76);  
tft.print(item_inside->serial);      //print SERIAL id
tft.setCursor(40,94);  
tft.print(encoder->displaycounter/10);      //print SERIAL id

}

void update_screen_colour(int background_colour,item_inside_struct* item_inside, device_info* device, encoder_struct* encoder)
{
screen_colour=background_colour;
tft.setTextColor(ST77XX_WHITE, background_colour);
tft.fillScreen(background_colour);
TFT_display(item_inside,device,encoder);
}

现在,我几乎将这3个结构传递给代码中的每一个函数,因为在某个时候会调用tft-update方法。有人能给我指明正确的方向吗?如何改进这个丑陋的代码?

尝试编写tft类

我重写了我的tft.c和tft.h,并在这个过程中学到了很多。我的tft.c:

include "tft_custom.h"

//class constructor, pass the 3 structures here
TFT::TFT(item_inside_struct &item_inside, device_info &device, encoder_struct &encoder){
Serial.println("calling tft class constructor");
screen_colour = ST77XX_BLACK ;
local_quantity = 0;
local_number_to_pick = 0;
local_displaycounter = 0;
strcpy(local_eeprom_serial,"NONE");
strcpy(local_current_status,"NONE");
strcpy(local_device_id,"NONE");
strcpy(local_device_version,"NONE");
strcpy(local_mqtt_server,"NONE");
class_item_inside = &item_inside;
class_device = &device;
class_encoder = &encoder;
}
void TFT::begin(){
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
tft.setTextColor(ST77XX_WHITE, ST77XX_BLACK);
tft.fillScreen(ST77XX_BLACK);
}

void TFT::update_display_once(){
tft.setTextSize(4); 
tft.setCursor(0, 0);    
tft.print(class_item_inside->quantity);   //quantity inside          
tft.setCursor(0,32);                  
tft.print(class_item_inside->num_to_pick);        // number2 means number to_pick
tft.setTextSize(1); 
tft.setCursor(120,0);
tft.print(class_device->device_version);

tft.setCursor(80,10);             
tft.print(class_device->mqtt_server);        // number2 means number to_pick

tft.setTextSize(2); 
tft.setCursor(64,32);
tft.print(class_item_inside->state);        
tft.setCursor(40,60); 
tft.print(class_device->DEVICE_ID);        
tft.setCursor(40,76);  
tft.print(class_item_inside->serial);      //print SERIAL id
tft.setCursor(40,94);  
tft.print(class_encoder->displaycounter/10);      //print SERIAL id
}

void TFT::TFT_display_update(){    
tft.setTextSize(4); 
if(local_quantity != class_item_inside->quantity)
{
tft.setCursor(0, 0);
tft.fillRect(0,0, 80, 32, screen_colour);
local_quantity = class_item_inside->quantity;
tft.print(local_quantity);   //quantity inside          

}

if(local_number_to_pick != class_item_inside->num_to_pick)
{
tft.setCursor(0,32);  
tft.fillRect(0,32, 40, 32, screen_colour); 
local_number_to_pick = class_item_inside->num_to_pick;               
tft.print(local_number_to_pick);        // number2 means number to_pick
}

tft.setTextSize(1); 
if(strcmp(local_device_version,class_device->device_version)!= 0)
{
tft.setCursor(120,0);  
tft.fillRect(120,0, 10, 10, screen_colour);
strcpy(local_device_version,class_device->device_version);          
tft.print(local_device_version);        // number2 means number to_pick
}

if(strcmp(local_mqtt_server,class_device->mqtt_server)!= 0)
{
tft.setCursor(80,10);  
tft.fillRect(80,10, 40, 5, screen_colour);                
strcpy(local_mqtt_server,class_device->mqtt_server);
tft.print(local_mqtt_server);        // number2 means number to_pick
}

tft.setTextSize(2);
if(strcmp(local_device_id,class_device->DEVICE_ID)!= 0){ 
tft.setCursor(40,60);
tft.fillRect(40,60, 50, 16, screen_colour);    
strcpy(local_device_id,class_device->DEVICE_ID);
tft.print(local_device_id); 

}     

if(strcmp(local_current_status,class_item_inside->state)!= 0){ 
tft.setCursor(40,32);
tft.fillRect(40,32, 120, 16, screen_colour);  
strcpy(local_current_status,class_item_inside->state);
tft.print(local_current_status); 
}  

if(strcmp(local_eeprom_serial,class_item_inside->serial) !=0)
{
tft.setCursor(40,76);
tft.fillRect(40,76, 120, 16, screen_colour);  
strcpy(local_eeprom_serial, class_item_inside->serial);
tft.print(local_eeprom_serial);      //print SERIAL id

}

if(local_displaycounter != class_encoder->displaycounter)
{
tft.setCursor(40,94); 
tft.fillRect(40,94, 60, 16, screen_colour);   
local_displaycounter = class_encoder->displaycounter;
tft.print(local_displaycounter/10);      //print SERIAL id
}

}


void TFT::update_screen_colour(int background_colour)
{
screen_colour=background_colour;
tft.setTextColor(ST77XX_WHITE, background_colour);
tft.fillScreen(background_colour);
update_display_once();
}

和tft.h:


#ifndef TFT_CUSTOM_H
#define TFT_CUSTOM_H
#include "Adafruit_ST7735.h" // Hardware-specific library for ST7735
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "definitions.h"
#define TFT_CS        5 // Hallowing display control pins: chip select
#define TFT_RST       4 // Display reset
#define TFT_DC        2 // Display data/command select
#define TFT_MOSI 19  // Data out
#define TFT_SCLK 18  // Clock out


class TFT
{
private:
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
//create 3 pointers to the struct
item_inside_struct *class_item_inside; 
device_info *class_device;
encoder_struct *class_encoder;
int screen_colour;
int local_quantity;
int local_number_to_pick;
char local_eeprom_serial[10];
char local_current_status[20];
int local_displaycounter;
char local_device_id[10] ;
char local_device_version[10];
char local_mqtt_server[20];
public:
TFT(item_inside_struct &item_inside, device_info &device, encoder_struct &encoder);
void begin();
void update_display_once();
void TFT_display_update();
void update_screen_colour(int background_colour);
};
#endif

在我的main.c中,我创建了一个类构造函数并传递这3个结构。在类构造函数中,我为所有3个结构创建一个指针,并在整个类中使用这3个指针

我的主要。c:


TFT tft_object(item_inside, device, encoder);
void setup() {
Serial.begin(115200);
pinMode(SENSOR, INPUT);    // sets the digital pin 13 as output
Expander_SETUP();
setup_leds();
tft_object.begin();
tft_object.update_display_once();
}
void loop() {
if(strncmp(item_inside.state, "PILDYMAS", 8) != 0)
{
Read_sensor_no_delay(tft_object);
}

请注意,在我的read_sensor_no_delay函数中,我将其传递给tft对象。在read_sensor函数中,我希望能够读取和写入类对象结构,如下所示:

void Read_sensor_no_delay(TFT &tft_object ){
sensor = digitalRead(SENSOR);
if(sensor==LOW  && sensor_prev_state==HIGH)// SENSOR ON
{
if (strncmp(tft_object.class_item_inside->state,"ACTIVE",6)!=0){ // IF NUMBER TO PICK ITEMS IS 0, SET RED LIGHT TO SHOW OPERATOR WRONG BOX
handle_activation(tft_object);
}

else if(sensor==HIGH && sensor_prev_state==LOW) //SENSOR DEACTIVATED
{ 
handle_deactivation(tft_object);
}
}

注意if (strncmp(tft_object.class_item_inside->state,"ACTIVE",6)!=0)内部读取传感器功能。然而,由于tft类中的所有变量都被声明为private,我遇到了一个问题。解决这个问题的唯一方法是将指向结构的3个指针声明为public吗?

当然没有正确的答案。如果你试图想出一个,一群人会跳上来告诉你为什么错了:-)

但是,有几个选择:

  1. 实际上有全局变量是可以的。它使人们更难理解代码以及值的来源等,但从技术上讲,这并不是";错误的";(也就是说,它进行编译是为了让编译器认为它还可以,对吧?)。您也可以使用goto语句;坏的";许多人也是如此。

  2. 有些代码将需要了解的变量的本地副本封装在文件中的static变量中。然后,您可以创建一个init_sensors()函数,该函数接受这三个指针并记住它们。

  3. 另一种常见的机制,可能是大多数raw-C代码中更喜欢的机制,是创建一个封装其他三个结构的指针,并将该指针作为第一个参数传递给几乎每个函数。这也为您的代码提供了一些未来证明,以防您需要添加第四个代码。类似于:

struct foo_context {
item_inside_struct* item_inside;
device_info* device;
encoder_struct* encoder;
}
  1. 您使用的是C++,但大部分代码感觉更像";C";喜欢更好地处理面向对象的特性可能也很有帮助,并尝试将更多的功能封装到对象中。IE,如果TFT*函数被封装在一个新的TFT对象中,那么你可以创建一次该对象,在其构造函数期间传递指针,并让它在类的实例处于活动状态时记住它们

这当然不是一个完整的答案,只是一个指向分离责任的指针,其他人已经提到了这一点。

让我们看看这部分:

读取传感器后,根据传感器结果,可能需要更新tft显示,因此我必须将所有结构数据传递给函数

这闻起来很难闻。读取传感器的代码不需要知道tft显示屏。可能有多个对象需要对传感器的状态变化做出一些反馈或其他反应——显示一些东西、闪烁一些LED、发出声音信号、将事件记录在一些文件中等。您只是不可能知道所有可能的未来需要更新的对象。并且您的代码不能依赖于表示这些对象的类。

一个解决方案可以是消息代理——一个了解不同参与者并在他们之间传输消息的对象(请参阅维基百科上的消息代理)。这可以只是一个主应用程序类的对象:item_inside_struct可以包含一个指向App对象的指针,该指针将负责正确处理(即调度)到其他设备的事件。

另一种方法可能是观察者(请参阅维基百科上的观察者模式)——应用程序中不同类的所有对象,可能以某种方式利用传感器状态的变化,都会在传感器类对象中注册(即通过将其自身附加到列表中),并在识别到变化时得到通知。然后,它们中的每一个都将产生适当的响应,而不需要知道传感器类别的细节。

最新更新