Pilotare un pannello LCD tipo TN con RA4M1

Girando su aliexpress ho notato questi piccoli lcd a 3 cifre ... sono pannelli in vetro senza driver con 3 cifre a 7 segmenti


Il microcontrollore RA4M1 (montato a bordo delle UNO R4) contiene al suo interno il modulo SLCDC che permette di gestire direttamente questi lcd senza driver. Purtroppo le UNO R4 non hanno abbastanza pin per collegare questi display, percio' ho sviluppato il progetto su una sua variante, la WeAct RA4M1 sulla quale ho caricato il bootloader della UNO R4 MINIMA, in questo modo Arduino IDE riconosce questa scheda come se fosse una R4 MINIMA con il vantaggio di avere nolti piu' pin disponibili.
L'uso di questi pannelli lcd e' molto utile nell'ottica del risparmio energetico perche' consumano correnti nell'ordine dei uA (microAmpere), percio' schede alimentate a batterie o con pannelli solari ... e poi saper gestire questo tipo di display puo' tornare utile per riciclare lcd di qualche vecchio oggetto che magari dovremmo buttare (radiosveglie, orologi ecc.).
Sul sito Aliexpress ho trovato poche informazioni tecniche riguardo questi pannelli, ho dovuto incrociare queste informazioni con quelle contenute nel datasheet dell'RA4M1 e fare diverse prove prima di vederlo funzionare.
Quado ,successivamente, parlo di datasheet faccio riferimento all'User’s Manual: Hardware. Questo il pinouts dell'lcd:

Ci sono 3 cifre con 7 segmenti ciascuna. Tutte e 3 le cifre hanno in comune 4 pin (COM0, COM1,COM2 e COM3), ogni cifra ha 2 pin dedicati (SEG1,SEG2,SEG3,SEG4,SEG5,SEG6). I segmenti si accendono quando viene creata una differenza di potenziale tra i pin SEG e i pin COM. Il segnale che alimenta i segmenti deve avere una frequenza di almeno 30Hz per evitare lo sfarfallio (dopo varie configurazioni ho optato per i 32Hz) e un ampiezza di 3V.
Come suggerito dal datasheet, nella tabella 45.6 a pag.1265, i pannelli con 4 pin comuni possono essere gestiti sia con 1/3 Bias che con 1/4 Bias... io ho testato 1/3 Bias con ottimi risultati! Ma cosa significa 1/3 Bias? Con i vecchi display a 7 segmenti a led bastava creare una differenza di potenziale pari all'alimentazione di ogni singolo segmento per accenderli, con 1/3 Bias l'alimentazione dei segmenti viene multiplexata ... ci sono 3 livelli di tensione (per i 3V abbiamo 1V, 2V e 3V), a segmento spento l'ampiezza del segnale oscilla tra 1V e 2V, questo permette una notevole velocita' di accensione/spegnimento dei segmenti (pensate al display di un cronometro usato in ambito sportivo!). Per lavorare a 1/3 Bias ci occorre avere questi 3 livelli di tensione sui pin del nostro RA4M1 (considerando che il nostro lcd lavora a 3Volt avremo 1V sul pin VL1 che corrisponde al pin P100, 2V sul pin VL2 il nostro P101 e 3V sul pin VL4 che corrisponde alla porta P103).

Per creare questo segnale ci sono 3 modalita':

  • External resistance division method: Dobbiamo portare noi sulla scheda i 3 livelli di tensione con 3 resistenze in serie tra Vcc e GND. NON ho testato al momento questo metodo
  • Internal Voltage Boosting Method: da usare su schede con Vcc a 5V ... il nostro processore ha un generatore interno che genera 3Volt e divide i 3 livelli di tensione sui pin P100,P101 e P103 che poi andra' a multiplexare per accendere e spegnere i segmenti (per utilizzare questa modalita' implementata nel programma che allego sotto, utilizzare la #define INTERNAL_VOLTAGE_BOOSTING)
  • Capacitor Split Method: Questo e' il metodo che sfrutta il massimo risparmio energetico perchè non usa il generatore interno per generare i 3Volt ma suddivide su 3 livelli la Vcc sempre sui pin P100,P101 e P103 Attenzione ad usare questo metodo SOLTANTO su schede con Vcc a 3.3Volt, altrimenti rischiate di bruciare il pannello lcd! per utilizzare questo metodo, utilizzare la #define CAPACITOR_SPLIT_METOD

Tra i pin P100, P101, P103 verso GND e a cavallo dei pin P111 e P112, il datasheet prevede 4 condensatori da 0.47uF che fungono da filtri.

Come si accendono i segmenti?
Per accendere i vari segmenti e creare numeri e lettere (nel limite dei 7 segmenti) occorre fare riferimento alla fig. 45.28 del datasheet a pag.1297:

A sinistra abbiamo la combinazione dei 2 segmenti dedicati ad ogni cifra con (a destra) i 4 pin comuni a tutte le cifre ... Se per esempio vogliamo far accendere il numero 1 sulla cifra a destra del nostro display SEG2n corrisponderà a SEG1 e SEG2n+1 a SEG2 ...

      |SEG1| SEG2|

|COM0 | 0 | 0 |
|COM1 | 1 | 0 |
|COM2 | 1 | 0 |
|COM3 | 0 | 0 |

il SEG1 sara' 0b0110 (0x06) e SEG0 0b0000 (0x00), percio' scrivendo:

  R_SLCDC->SEG[1] = 0x06;
  R_SLCDC->SEG[2] = 0x00;

Si accendera' il numero 1 sulla cifra piu' a destra :smiley:

Ho testato un programma che visualizza la temperatura della CPU sul dislpay con la funzione lcd_display_3dig(int32_t value); che permette di visualizzare valori tra -99 e 999 ...

#include "analog.h"

// With Capacitor split metod, LCD drive voltage has same level of RA4M1 Vcc (USE IT ONLY IF Vcc of RA4M1 is 3.3V)
// Capacitor split metod not require continuous current flow, and therefore the current consuption can be reduced
//#define CAPACITOR_SPLIT_METOD

// Internal voltage boosting metod allow you to choose LCD drive voltage by VLCD register
// RA4M1 enable internal voltage boost circuit that supply a constant voltage, regardless of changes in Vcc
#define INTERNAL_VOLTAGE_BOOSTING

#define PERIOD         1000
#define SLOPE          -0.00365  // Sensibilità del sensore di temperatura V/℃ ((vs - v1) / (24 - 125)) --> Correggere qui eventuale errore di temperatura reale/misurata (con termometro su chip)
#define VREF           1.43     // Tensione interna di riferimento (secondo il datascheet Typ:1.43V Min:1.36V Max:1.50V)

float degC, vCC;
adc_status_t status;
adc_info_t adc_info;

const uint8_t char_number[] = { // Numeri da visualizzare sul display
        0x7d, 0x60, 0x3e, 0x7a, 0x63, 0x5b, 0x5f, 0x70, 0x7f, 0x7b /* 0-9 */
};

void setup() {
  setupLCD();
  Serial.begin(115200);
  delay(2000);
}


void loop() {
  static uint32_t last = millis();
  uint32_t now = millis();
  if(now - last >= PERIOD) {
    last = now;
    degC  = readTemp();         // Misurazione della temperatura con sensore integrato nella CPU
   lcd_display_3dig((int)degC); // Visualizza la temperatura sul display
   Serial.print("Temp:");Serial.print(degC, 2);Serial.println("°C");  // Temperatura in uscita su seriale
  }

}

void lcd_display_3dig(int32_t value) { // Visualizza un valore numerico compreso tra -99 e 999
     bool negative = false; // flag che indica un valore negativo
      if((int)value<0){     // Se il valore e' negativo
      value = value * -1;   // non considera il segno meno
      negative = true; // ma tiene conto del segno meno con il flag "negative"
      }
  //uint8_t thousands = (uint8_t)((value % 10000) / 1000); // Da usare SOLTANTO su lcd a 4 cifre
    uint8_t hundreds = (uint8_t)((value % 1000) / 100); // scompone il valore in centinaia ...
    uint8_t tens= (uint8_t)((value % 100) / 10);        // decine ...
    uint8_t units= (uint8_t)((value % 10) / 1);         // e unita' ...    
      // Ogni cifra sul display è rappresentata da 2 segmenti
    R_SLCDC->SEG_b[1].A = char_number[(units)] >> 4;  // visualizza le unita' sulla cifra a destra del display
    R_SLCDC->SEG_b[2].A = char_number[(units)] & 0x0f; // la cifra a destra del display e' pilotata dai segmenti 1 & 2
    if(tens){ // Se il valore ha cifre dedimali le stampa sul display
    R_SLCDC->SEG_b[3].A = char_number[(tens)] >> 4; // visualizza le decine' sulla cifra al centro del display
    R_SLCDC->SEG_b[4].A = char_number[(tens)] & 0x0f; // la cifra centrale del display e' pilotata dai segmenti 3 & 4
    }
    if((tens == 0) && (negative == true)){ // Se il valore non ha cifre decimali ma e' negativo, stampa "-" a sinistra delle unita'
     R_SLCDC->SEG_b[3].A = 0x00; // "-" e' rappresentato con il valore 0x02
     R_SLCDC->SEG_b[4].A = 0x02; 
    }
    if(hundreds){ // Se il valore ha cifre centesimali
    R_SLCDC->SEG_b[5].A = char_number[(tens)] >> 4; // visualizza le centinaia sulla cifra a sinistra del display
    R_SLCDC->SEG_b[6].A = char_number[(tens)] & 0x0f; // la cifra a sinistra del display e' pilotata dai segmenti 5 & 6
    }
    if((hundreds == 0) && (negative == true)){ // Se il valore non ha cifre centesimali ma e' negativo, stampa "-" a sinistra delle decine'
     R_SLCDC->SEG_b[5].A = 0x00; // "-" e' rappresentato con il valore 0x02
     R_SLCDC->SEG_b[6].A = 0x02; 
    }
}

void setupLCD(){
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_01, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG01
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_03, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG03
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_00, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG04
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_01, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG05
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG06
  
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_04, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM0
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_05, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM1
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_06, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM2
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_07, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM3
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_11, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // CAPH
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_12, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // CAPL
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_00, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL1
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_01, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL2
  //R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // VL3
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_03, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL4
  
  R_MSTP->MSTPCRC_b.MSTPC4 = 0;  // Enable SLCDC module

  /*8.7.11 Segment LCDC Source Clock (LCDSRCCLK)
  The Segment LCDC source clock, LCDSRCCLK, is the operating clock for the SLCDC.
  The LCDSRCCLK is specified by the LCDSCKSEL[2:0] bits in SLCDSCKCR.
  LCDSRCCLK is output when SLCDSCKCR.LCDSCKEN is set to 1. When changing the value of
  SLCDSCKCR.LCDSCKSEL[2:0], make sure that the value of SLCDSCKCR.LCDSCKEN is 0.*/
  R_SYSTEM->PRCR = 0xA501;
  R_SYSTEM->SLCDSCKCR = 0x80;  // Enable LOCO clock as LCD source clock (see 8.2.19 Segment LCD Source Clock Control Register)
  R_SYSTEM->PRCR = 0xA501;


#ifdef INTERNAL_VOLTAGE_BOOSTING
R_SLCDC->LCDM1_b.LCDVLM = 0;
R_SLCDC->LCDM0 = 0x4D; //Internal voltage boosting method
R_SLCDC->VLCD = 0x04;  // Reference Voltage = 3V
delay(10);
#endif

#ifdef CAPACITOR_SPLIT_METOD
R_SLCDC->LCDM0 = 0x8D; //Capacitor split method 
#endif

R_SLCDC->LCDC0 = 0x07;         // 128Hz means 32Hz with 1/3 bias
R_SLCDC->LCDM1_b.VLCON = 1; //Enable voltage boosting circuit operation
  delay(10);
  R_SLCDC->LCDM1_b.SCOC = 1;
  R_SLCDC->LCDM1_b.LCDON = 1;
}

void lcd_display_close(){  
  R_SLCDC->LCDM1 = (uint8_t)(R_SLCDC->LCDM1 &(~(0xC0))); //Stop SLCD output  
  R_SLCDC->LCDM1_b.VLCON = 0; //Stop voltage boost circuit or capacitor split circuit operation  
  R_SLCDC->LCDM0_b.MDSET = 0; //Switch to external resistance method to reduce idle power consuption
  
  R_SYSTEM->PRCR = 0xA501;
  R_SYSTEM->SLCDSCKCR_b.LCDSCKEN = 0; //Disable lcd clock
  R_SYSTEM->PRCR = 0xA501;

  R_MSTP->MSTPCRC_b.MSTPC4 = 1; //Enter module-stop state for the SLCDC
}

float readTemp(){
  ADC_Container adc(0, NULL);
  uint16_t adc_data = 0; // R_ADC0->ADTSDR & 0xFFFF;
  float mcu_temp_c = 0;
  int16_t v125;
  float v1,vs;
  vCC   = readVcc();
  adc.cfg.resolution        = ADC_RESOLUTION_12_BIT;
  adc.channel_cfg.scan_mask = ADC_MASK_TEMPERATURE; //ADEXICR
  analogReference(AR_INTERNAL);
  R_ADC_Open(&adc.ctrl, &adc.cfg);
  R_ADC_ScanCfg(&adc.ctrl, &adc.channel_cfg);
  R_ADC_ScanStart(&adc.ctrl); // ADCSR.ADST
  delay(1);
    R_ADC_Read (&adc.ctrl, ADC_CHANNEL_TEMPERATURE, &adc_data);
    while( ADC_STATE_SCAN_IN_PROGRESS == status.state) {
     R_ADC_StatusGet(&adc.ctrl, &status);
    }
    R_ADC_InfoGet(&adc.ctrl, &adc_info);   
    v125 = (int16_t) adc_info.calibration_data; // v125   = (R_TSN->TSCDRH << 8) + R_TSN->TSCDRL
    v1 = 3.3f * v125 / 4096; // Voltage output by the TNS at 125 degreeC
    vs = vCC * adc_data / 4096; // Voltage output by the TNS at the time of measurement of T1 (volt)
    //Serial.print("vs: ");Serial.print(vs);Serial.print(" v1: ");Serial.println(v1);
    mcu_temp_c = (vs - v1) / SLOPE + 125;
    //Serial.println(mcu_temp_c);
    R_ADC_Close(&adc.ctrl);
    return mcu_temp_c;
}

float readVcc(){
ADC_Container adc(0,NULL);
adc.cfg.resolution               = ADC_RESOLUTION_12_BIT;
adc.channel_cfg.scan_mask        = ADC_MASK_VOLT;//ADEXICR
adc.cfg_extend.adc_vref_control  = ADC_VREF_CONTROL_AVCC0_AVSS0; //ADHVREFCNT
uint16_t adc_data = 0; // R_ADC0->ADOCDR & 0xFFFF;
float vCC;
R_ADC_Open(&adc.ctrl, &adc.cfg);
R_ADC_ScanCfg(&adc.ctrl, &adc.channel_cfg);
R_ADC_ScanStart(&adc.ctrl);// ADCSR.ADST
delay(1);
R_ADC_Read (&adc.ctrl, ADC_CHANNEL_VOLT, &adc_data);
    while( ADC_STATE_SCAN_IN_PROGRESS == status.state) {
     R_ADC_StatusGet(&adc.ctrl, &status);
    }
    vCC = (VREF * 4096) / adc_data; //4096 12bit - 16383 14bit
    //Serial.print("Vcc: ");Serial.print(vCC);Serial.println("V");
    R_ADC_Close(&adc.ctrl);
    return vCC;
}

Infine, un saluto con la scritta "CIAO" che scorre sul dislpay...

// With Capacitor split metod, LCD drive voltage has same level of RA4M1 Vcc (USE IT ONLY IF Vcc of RA4M1 is 3.3V)
// Capacitor split metod not require continuous current flow, and therefore the current consuption can be reduced
//#define CAPACITOR_SPLIT_METOD

// Internal voltage boosting metod allow you to choose LCD drive voltage by VLCD register
// RA4M1 enable internal voltage boost circuit that supply a constant voltage, regardless of changes in Vcc
#define INTERNAL_VOLTAGE_BOOSTING



const uint8_t char_number[] = {
        0x7d, 0x60, 0x3e, 0x7a, 0x63, 0x5b, 0x5f, 0x70, 0x7f, 0x7b /* 0-9 */
};
const uint8_t char_CIAO[] = {
        0x1d, 0x60, 0x77, 0x7d /* C-I-A-O */
};
const uint8_t char_Err[] = {
        0x1f, 0x06, 0x06 /* E-r-r */
};

void setup() {
  Serial.begin(115200);
  delay(2000);
  setupLCD();
  //lcd_display_3dig(-87);
  //display_Err(); // Visualizza la scritta "Err"
  display_CIAO(); // Scorre la parola CIAO sul display
}

void loop() {
  //display_CIAO();

}

void display_CIAO(){
  // Primo screen C
    R_SLCDC->SEG_b[1].A = char_CIAO[0] >> 4; 
    R_SLCDC->SEG_b[2].A = char_CIAO[0] & 0x0f;
    delay(500);
    // Secondo screen CI
    R_SLCDC->SEG_b[3].A = char_CIAO[0] >> 4; 
    R_SLCDC->SEG_b[4].A = char_CIAO[0] & 0x0f;
    R_SLCDC->SEG_b[1].A = char_CIAO[1] >> 4; 
    R_SLCDC->SEG_b[2].A = char_CIAO[1] & 0x0f;
    delay(500);
    // Terzo screen CIA
    R_SLCDC->SEG_b[5].A = char_CIAO[0] >> 4; 
    R_SLCDC->SEG_b[6].A = char_CIAO[0] & 0x0f;
    R_SLCDC->SEG_b[3].A = char_CIAO[1] >> 4; 
    R_SLCDC->SEG_b[4].A = char_CIAO[1] & 0x0f;
    R_SLCDC->SEG_b[1].A = char_CIAO[2] >> 4; 
    R_SLCDC->SEG_b[2].A = char_CIAO[2] & 0x0f;
    delay(500);
    //Quarto screen IAO
    R_SLCDC->SEG_b[5].A = char_CIAO[1] >> 4; 
    R_SLCDC->SEG_b[6].A = char_CIAO[1] & 0x0f;
    R_SLCDC->SEG_b[3].A = char_CIAO[2] >> 4; 
    R_SLCDC->SEG_b[4].A = char_CIAO[2] & 0x0f;
    R_SLCDC->SEG_b[1].A = char_CIAO[3] >> 4; 
    R_SLCDC->SEG_b[2].A = char_CIAO[3] & 0x0f;
    delay(500);
    // Quinto screen AO
    R_SLCDC->SEG_b[5].A = char_CIAO[2] >> 4; 
    R_SLCDC->SEG_b[6].A = char_CIAO[2] & 0x0f;
    R_SLCDC->SEG_b[3].A = char_CIAO[3] >> 4; 
    R_SLCDC->SEG_b[4].A = char_CIAO[3] & 0x0f;
    R_SLCDC->SEG_b[1].A = 0; 
    R_SLCDC->SEG_b[2].A = 0;
    delay(500);
    //Sesto screen O
    R_SLCDC->SEG_b[5].A = char_CIAO[3] >> 4; 
    R_SLCDC->SEG_b[6].A = char_CIAO[3] & 0x0f;
    R_SLCDC->SEG_b[3].A = 0; 
    R_SLCDC->SEG_b[4].A = 0;
    R_SLCDC->SEG_b[1].A = 0; 
    R_SLCDC->SEG_b[2].A = 0;
    delay(500);
    //Settimo screen vuoto
    R_SLCDC->SEG_b[5].A = 0; 
    R_SLCDC->SEG_b[6].A = 0;
    R_SLCDC->SEG_b[3].A = 0; 
    R_SLCDC->SEG_b[4].A = 0;
    R_SLCDC->SEG_b[1].A = 0; 
    R_SLCDC->SEG_b[2].A = 0;
    delay(500);
}

void display_Err(){
    R_SLCDC->SEG_b[1].A = char_Err[2] >> 4; 
    R_SLCDC->SEG_b[2].A = char_Err[2] & 0x0f;
    R_SLCDC->SEG_b[3].A = char_Err[1] >> 4; 
    R_SLCDC->SEG_b[4].A = char_Err[1] & 0x0f;
    R_SLCDC->SEG_b[5].A = char_Err[0] >> 4; 
    R_SLCDC->SEG_b[6].A = char_Err[0] & 0x0f;
    }

void lcd_display_3dig(int32_t value) { // Visualizza un valore numerico compreso tra -99 e 999
     bool negative = false; // flag che indica un valore negativo
      if((int)value<0){     // Se il valore e' negativo
      value = value * -1;   // non considera il segno meno
      negative = true; // ma tiene conto del segno meno con il flag "negative"
      }
    //uint8_t thousands = (uint8_t)((value % 10000) / 1000); // Da usare SOLTANTO su lcd a 4 cifre
    uint8_t hundreds = (uint8_t)((value % 1000) / 100); // scompone il valore in centinaia ...
    uint8_t tens= (uint8_t)((value % 100) / 10);        // decine ...
    uint8_t units= (uint8_t)((value % 10) / 1);         // e unita' ...    
      // Ogni cifra sul display è rappresentata da 2 segmenti
    R_SLCDC->SEG_b[1].A = char_number[(units)] >> 4;  // visualizza le unita' sulla cifra a destra del display
    R_SLCDC->SEG_b[2].A = char_number[(units)] & 0x0f; // la cifra a destra del display e' pilotata dai segmenti 1 & 2
    if(tens){ // Se il valore ha cifre dedimali le stampa sul display
    R_SLCDC->SEG_b[3].A = char_number[(tens)] >> 4; // visualizza le decine' sulla cifra al centro del display
    R_SLCDC->SEG_b[4].A = char_number[(tens)] & 0x0f; // la cifra centrale del display e' pilotata dai segmenti 3 & 4
    }
    if((tens == 0) && (negative == true)){ // Se il valore non ha cifre decimali ma e' negativo, stampa "-" a sinistra delle unita'
     R_SLCDC->SEG_b[3].A = 0x00; // "-" e' rappresentato con il valore 0x02
     R_SLCDC->SEG_b[4].A = 0x02; 
    }
    if(hundreds){ // Se il valore ha cifre centesimali
    R_SLCDC->SEG_b[5].A = char_number[(tens)] >> 4; // visualizza le centinaia sulla cifra a sinistra del display
    R_SLCDC->SEG_b[6].A = char_number[(tens)] & 0x0f; // la cifra a sinistra del display e' pilotata dai segmenti 5 & 6
    }
    if((hundreds == 0) && (negative == true)){ // Se il valore non ha cifre centesimali ma e' negativo, stampa "-" a sinistra delle decine'
     R_SLCDC->SEG_b[5].A = 0x00; // "-" e' rappresentato con il valore 0x02
     R_SLCDC->SEG_b[6].A = 0x02; 
    }
}

void setupLCD(){
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_01, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG01
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG02
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_03_PIN_03, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG03
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_00, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG04
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_01, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG05
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_04_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // SEG06
  
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_04, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM0
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_05, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM1
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_06, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM2
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_07, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // COM3
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_11, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // CAPH
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_12, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // CAPL
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_00, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL1
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_01, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL2
  //R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_02, IOPORT_PERIPHERAL_LCDC | IOPORT_CFG_PERIPHERAL_PIN); // VL3
  R_IOPORT_PinCfg(NULL, BSP_IO_PORT_01_PIN_03, IOPORT_PERIPHERAL_LCDC   | IOPORT_CFG_PERIPHERAL_PIN); // VL4
  
  R_MSTP->MSTPCRC_b.MSTPC4 = 0;  // Enable SLCDC module

  /*8.7.11 Segment LCDC Source Clock (LCDSRCCLK)
  The Segment LCDC source clock, LCDSRCCLK, is the operating clock for the SLCDC.
  The LCDSRCCLK is specified by the LCDSCKSEL[2:0] bits in SLCDSCKCR.
  LCDSRCCLK is output when SLCDSCKCR.LCDSCKEN is set to 1. When changing the value of
  SLCDSCKCR.LCDSCKSEL[2:0], make sure that the value of SLCDSCKCR.LCDSCKEN is 0.*/
  R_SYSTEM->PRCR = 0xA501;
  R_SYSTEM->SLCDSCKCR = 0x80;  // Enable LOCO clock as LCD source clock (see 8.2.19 Segment LCD Source Clock Control Register)
  R_SYSTEM->PRCR = 0xA501;


#ifdef INTERNAL_VOLTAGE_BOOSTING
R_SLCDC->LCDM1_b.LCDVLM = 0;
R_SLCDC->LCDM0 = 0x4D; //Internal voltage boosting method
R_SLCDC->VLCD = 0x04;  // Reference Voltage = 3V
delay(10);
#endif

#ifdef CAPACITOR_SPLIT_METOD
R_SLCDC->LCDM0 = 0x8D; //Capacitor split method 
#endif

R_SLCDC->LCDC0 = 0x07;         // 128Hz means 32Hz with 1/3 bias
R_SLCDC->LCDM1_b.VLCON = 1; //Enable voltage boosting circuit operation
  delay(10);
  R_SLCDC->LCDM1_b.SCOC = 1;
  R_SLCDC->LCDM1_b.LCDON = 1;
}

void lcd_display_close(){  
  R_SLCDC->LCDM1 = (uint8_t)(R_SLCDC->LCDM1 &(~(0xC0))); //Stop SLCD output  
  R_SLCDC->LCDM1_b.VLCON = 0; //Stop voltage boost circuit or capacitor split circuit operation  
  R_SLCDC->LCDM0_b.MDSET = 0; //Switch to external resistance method to reduce idle power consuption
  
  R_SYSTEM->PRCR = 0xA501;
  R_SYSTEM->SLCDSCKCR_b.LCDSCKEN = 0; //Disable lcd clock
  R_SYSTEM->PRCR = 0xA501;

  R_MSTP->MSTPCRC_b.MSTPC4 = 1; //Enter module-stop state for the SLCDC
}
4 Likes

Ne ho presi anch'io un lotto perché pensavo che si potesse farli funzionare a multiplex a 30-50hz normalmente come tutti i LCD di quel tipo, invece ho visto che bisogna mettere partitori di resistenza ovunque (ovvero il "External resistance division method:" che Citi) quindi li ho messi da parte, non ho intenzione di farli funzionare con MC dedicati e il metodo a condensatori che hai usato tu limita la scelta del MC
Comunque ottimo lavoro

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.