74HC595 с 4-значным 7-сегментным дисплеем. Есть ли способ избавиться от ведущих нулей?

Я работаю над считывателем температуры на базе Arduino, используя ИС температуры DS18B20. Дисплей представляет собой 4-значный 7-сегментный светодиодный дисплей с общим анодом, управляемый одним сдвиговым регистром 74HC595. В настоящее время он настроен на считывание переменной, назначенной числом, для тестирования части дисплея. Он отображает число с точностью до десятых долей после запятой, но у меня возникают проблемы при попытке избавиться от ведущих нулей. Когда переменной 'tempF' присваивается число, например 12.3, дисплей выдает 012.3, а если переменной присваивается число, например 1.2, дисплей выдает 001.2. В то же время я хотел, чтобы она ставила знак минус (-), когда число меньше нуля. Пока что примеры, которые я нахожу в Интернете, не соответствуют коду, с которым я сейчас работаю, или вообще не работают. Я не смог найти скетч, который бы работал для этого типа установки. Я разместил ниже код, с которым я работаю. Оригинальный код был получен по ссылке, указанной в скетче.

В скетче не предусмотрены средства считывания отрицательных температур или подавления ведущих нулей.


   /*
 * www.pial.net/arduino-controlling-a-4-digit-seven-segment-display/
 */

//#include <OneWire.h>
//#include <DallasTemperature.h>

//#define ONE_WIRE_BUS 2

//OneWire oneWire(ONE_WIRE_BUS);
//DallasTemperature sensors(&oneWire);
//DeviceAddress insideThermometer;

const int ledPin =  13;// LED connected to digital pin 13
const int latchPin = 8;//Pin connected to ST_CP of 74HC595
const int clockPin = 9;//Pin connected to SH_CP of 74HC595
const int dataPin = 10;//Pin connected to DS of 74HC595

const int digitPins[4] = {
  3,4,5,6}; //pins to control the 4 common anode pins of the display

const byte digit[10] = //seven segment digit bits
{
  B00111111, //0
  B00000110, //1
  B01011011, //2
  B01001111, //3
  B01100110, //4
  B01101101, //5
  B01111101, //6
  B00000111, //7
  B01111111, //8
  B01101111, //9
//  B00000000, //all segments off
//  B01000000 //-
};

int digitBuffer[4] = {
  1};
int digitScan = 0;
int soft_scaler = 0;
float tempC, tempF;
int tmp;

void setup()   {                
  TCCR2A = 0;
  TCCR2B = (1<<CS21);
  TIMSK2 = (1<<TOIE2);
  TCNT2 = 0;
  Serial.begin(9600);

  pinMode(ledPin, OUTPUT); 
  for(int i=0;i<4;i++)
  {
    pinMode(digitPins[i],OUTPUT);
  }
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  

//  sensors.begin();
//  sensors.getAddress(insideThermometer, 0);
}

ISR(TIMER2_OVF_vect) {
  soft_scaler++;
  if(soft_scaler==15)
  {
    refreshDisplay();
    soft_scaler = 0;
  }
};  

void refreshDisplay()
{
  for(byte k=0;k<4;k++)
  {
    digitalWrite(digitPins[k], LOW);
  }
  digitalWrite(latchPin, LOW);  
  shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
  digitalWrite(latchPin, HIGH);
  delayMicroseconds(50);
  digitalWrite(digitPins[digitScan], HIGH); 

  digitalWrite(latchPin, LOW);
//  if (digitScan==3)
//  {
//    shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitBuffer[digitScan]] | B00000000)); //inserting the blank
//    }
//    else
//  {
//    shiftOut(dataPin, clockPin, MSBFIRST, digit[digitBuffer[digitScan]]);
//  }

  if(digitScan==1)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitBuffer[digitScan]] | B10000000)); //inserting the dot
  }
  else
  {
    shiftOut(dataPin, clockPin, MSBFIRST, ~digit[digitBuffer[digitScan]]);
  }
  digitalWrite(latchPin, HIGH);
  digitScan++;
  if(digitScan>3) digitScan=0;
}

void loop()                     
{ 
  digitalWrite(ledPin, HIGH);
  boolean sign = false;
  //sensors.requestTemperatures();
  //tempC = sensors.getTempC(insideThermometer);
  //tempF = DallasTemperature::toFahrenheit(tempC);
  //tmp = int(tempF*100);
  tempF = 0.2;
  tmp = int(tempF*10);

//   if (digitScan == 4 ){
//    shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitScan] | B00000000)); //inserting the blank
//    }
//    else
//  {
//    shiftOut(dataPin, clockPin, MSBFIRST, digit[digitBuffer[digitScan]]);
//  }

//if (tmp < 0){
//sign = true;
//tmp = abs(tmp);
//}

//if (digitScan == 3) {
//  if (tmp < 0){
//    shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitBuffer[digitScan]] | B01000000)); // outputs minus sign
//  }
//  else {
//    shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitBuffer[digitScan]] | B00000000));
//   }

//  tmp = abs(tmp);
// }   
//  else if (digitScan == 3 && digit[digitScan-1] == 0) { // writing on the second display (tens; if there are none, outputs nothing)
//     shiftOut(dataPin, clockPin, MSBFIRST, ~(digit[digitBuffer[digitScan]] | B00000000));
//   }
//   else if (i == 2) { // writing on the third display, where decimal point is needed
//     shiftOut(data_pin, clk_pin, MSBFIRST, digit[digitBuffer[i-1]]);
//   }
//   else { // writing on "other" displays (in fact fourth display AND seecond display only if there are some tens)
//     shiftOut(data_pin, clk_pin, MSBFIRST, digit[digitBuffer[i-1]]);
//   }

  digitBuffer[3] = int(tmp)/1000;
  digitBuffer[2] = (int(tmp)%1000)/100;
  digitBuffer[1] = (int(tmp)%100)/10;
  digitBuffer[0] = (int(tmp)%100)%10;
  Serial.print("number assigned to the variable 'tmp' = ");
  Serial.println(tmp);
  Serial.print("number assigned to the variable 'tempF' = ");
  Serial.println(tempF);
  digitalWrite(ledPin, LOW);
  delay(500);
}

Закомментированные команды в скетче были попытками удалить ведущие нули и добавить знак минус, когда это было необходимо, но не увенчались успехом. Я также разместил схему проекта. Микросхема 74HC595 была использована таким образом, чтобы освободить выводы для последующего использования в проекте глубокой заморозки.

Я ни в коем случае не являюсь опытным программистом, но если кто-то может помочь мне или дать какое-то представление о том, как решить эту проблему, я буду очень признателен.

Есть ли способ избавиться от ведущих нулей?

Конечно, но два условия должны быть верны:

  1. у вас есть информация о шрифте для "blank"; для этого вам нужно снять комментарий в коде.

  2. вам нужно избавиться от ведущих нулей после вычисления буфера дисплея.

  displayBuffer[0]=(displayBuffer[0]==0)?FONT_BUFFER:displayBuffer[0]; //eliminate leading zero for displayBuffer[0]
  displayBuffer[1]=((displayBuffer[1]==0) && (displayBuffer[0]==FONT_BUFFER))?FONT_BUFFER:displayBuffer[1];
  ...

редактировать:

вот пример реализации концепции, описанной выше, на PIC12F675, управляющем двумя HC595. Число, которое нужно вывести на 4-значный дисплей - "12". Бланкирование сделано на первых трех цифрах -> вы можете убедиться в этом, посмотрев на значение дисплейного буфера lRAM[4]. 0x11 - это мой обозначитель пробела.

Неполное отображение '1' обусловлено мультиплексированием. Код в основном основан на том, что я написал здесь: https://dannyelectronics.wordpress.com/2017/03/03/driving-7-segment-leds/, модифицированный для управления через HC595s.

Это должно работать на любой микросхеме с минимальными изменениями.

edit 2: вот ваш код, управляющий CC дисплеем напрямую. число, которое должно отображаться на дисплее, 1.23, с убранными ведущими нулями в старших двух цифрах.

Комментарии (4)