Eric_O
Advanced Member level 4
Bonjour,
Would like to display 2 or 3 decimals on LCD.
For example, display 22,5; or 22,50; or 22,500.
But would like to display 22,57; or 22,524 for example.
Would like to display 2 or 3 decimals on LCD.
For example, display 22,5; or 22,50; or 22,500.
But would like to display 22,57; or 22,524 for example.
Code:
// MCU : PIC 16F887
// External clock : Quartz 4 MHz
// LED YELLOW is connected to pin 17 (portc.b2).
// LED GREEN is connected to pin 18 (portc.b3).
// Switch is connected to pin 21 (portd.b2).
// Switch is connected to pin 22 (portd.b3).
// LM35 temperature sensor : pin GND to GND,
// pin DQ to pin 5 (AN3),
// pin VCC to VCC.
/******************************************************************************/
//#include <math.h> // A re tester en décochant dans View > Library Manager > C_Math.
// Fonction floor() dans float_to_ASCII_with_2_decimals_v4
/******************************************************************************/
// LCD module connections :
// VSS (pin 1) -> GND
// VDD (pin 2) -> VCC
// VEE (pin 3) -> middle pin contrast potentiometer
sbit LCD_RS at RB4_bit; // RS (pin 4) -> portB.b4 (pin 37)
// RW not used. // RW (pin 5) -> GND
sbit LCD_EN at RB5_bit; // EN (pin 6) -> portB.b5 (pin 38)
// D0 (pin 7) -> GND
// D1 (pin 8) -> GND
// D2 (pin 9) -> GND
// D3 (pin 10) -> GND
sbit LCD_D4 at RB0_bit; // D4 (pin 11) -> portB.b0 (pin 33)
sbit LCD_D5 at RB1_bit; // D5 (pin 12) -> portB.b1 (pin 34)
sbit LCD_D6 at RB2_bit; // D6 (pin 13) -> portB.b2 (pin 35)
sbit LCD_D7 at RB3_bit; // D7 (pin 14) -> portB.b3 (pin 36)
// (pin 15) -> GND
// (pin 16) -> GND
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
/******************************************************************************/
#define CMD 0
#define DATA 1
#define LCD_PORT PORTB
#define LCD_COLUMNS 16
/******************************************************************************/
// Declaration of variables :
char texte[64]; // 0 to 255
// Variables ci-dessous sorties du main() pour les déclarer en global.
// Le PIC 16F a moins de mémoire RAM et ROM que le PIC 18F.
unsigned char *pointeur_de_char; // Déclaration d'un pointeur (*) de char "pointeur_de_char".
unsigned char i;
char ROW[] = {0x80, 0xC0};
/******************************************************************************/
// Routines :
void ADC_initialization()
{
ADCON0 = 0b01000001; // b0 = 1 (ADON) : le convertisseur A/N interne est activé.
// b1 (GO/DONE) : A/D Conversion Status bit.
// b2, b3, b4, b5 (CHS0, CHS1, CHS2, CHS3) : Analog Channel Select bits.
// b6 = 1 (ADSC0), b7 = 0 (ADSC1) : fosc / 8 = 4 MHz / 8 = 0,5 MHz = 500 KHz
// tosc = 1 / fosc = 1 / 500 KHz = 0,002 mS = 2 uS.
// 2 uS est le temps de conversion A/D d'un bit, TAD.
// Pour une conversion totale sur 10 bits il faut 12 TAD.
// Pour une conversion correcte il faut que TAD = 1,6 uS au minimum.
// TAD = 2 uS / bit. 12 TAD = 24 uS pour 10 bits.
ADCON1 = 0b10000000; // b0 = b1 = b2 = b3 = 0 : Unimplemented. Read as '0'.
// b4 = 0 (VCFG0) : Voltage reference VDD.
// b5 = 0 (VCFG1) : Voltage reference VSS.
// b6 = 0 : Unimplemented. Read as '0'.
// b7 = 1 : ADFM (A/D result ForMat) = 1 (format justifié à droite).
// Explication :
// ADRESH | ADRESL
// b7|b6|b5|b4|b3|b2|b1|b0|b7|b6|b5|b4|b3|b2|b1|b0
// 0| 0| 0| 0| 0| 0| r| r| r| r| r| r| r| r| r| r
// les 6 MSB = 0 | résultat r sur 10 bits
}
unsigned int ADC_read(unsigned char channel)
// Si message d'erreur "'ADC_read' Identifier redefined" pendant compilation, dans Library Manager décocher ADC_Read.
// ADC_read est ma propre routine écrite pour apprentissage. Je n'utilise pas ADC_Read de la librairie Mikroelektronika.
{
static unsigned int k; // Variable locale (static).
ADCON0 = ADCON0 & 0b11000011; // ADCON0 = 01000001
// & 11000011 (masque)
// ADCON0 = 01000001
// masque :
// b0 = 1 (ADON) : pour prendre en compte l'état du convertisseur A/D, en service (0) ou à l'arrêt (1).
// b1 = 1 (GO/DONE) : pour prendre en compte l'état de la conversion A/D, en cours (1) ou terminée (0).
// b2 = b3 = b4 = b5 = 0 (CHS0 CHS1 CHS2 CHS3) : pour re initialiser au premier canal de conversion, le canal 0 (CHS0 = CHS1 = CHS2 = CHS3 = 0).
// b6 = b7 = 1 (ADSC0 ADSC1) : pour prendre en compte la valeur du diviseur, de la vitesse de conversion, choisi.
channel = channel << 2; // Décalage channel de 2 bits à gauche pour placer la valeur de channel dans bits b2 b3 b4 b5 (CHS0 CHS1 CHS2 CHS3).
ADCON0 = ADCON0 | channel; // OU logique bit à bit entre ADCON0 et channel.
// ou ADCON0 |= channel;
Delay_ms(2); // Délais de 2 mS minimum. >>> A ajuster si besoin. <<<
ADCON0.GO_DONE = 1; // Déclenchement de la conversion A/N.
// ou ADCON0.b2 = 1;
_asm NOP; // Recommandé par Microchip.
while (ADCON0.GO_DONE == 1); // Attendre que le bit GO.DONE passe à 0.
{
k = ADRESL + (ADRESH * 256); // XXX A REVOIR XXX
//ou k = ADRESL + (ADRESH << 8);
}
return(k);
}
void LCD_E_Pulse(void)
{
LCD_EN = 1;
Delay_us(8); // Delay between 5 uS and 10 uS.
LCD_EN = 0;
Delay_us(500); // Delay between 5 uS and 1000 uS (1 mS).
}
void LCD_Write(unsigned char cmd_or_data, unsigned char byte)
{
unsigned char low, high;
high = (byte >> 4) & 0x0F; // b7 b6 b5 b4 of byte are shifted to b3 b2 b1 b0 of byte and saved in high.
low = byte & 0x0F; // b3 b2 b1 b0 of byte are saved in low.
LCD_PORT = high; // Send higher nibble of byte to the LCD.
LCD_RS = cmd_or_data;
LCD_E_Pulse();
LCD_PORT = low; // Send lower nibble of byte to the LCD.
LCD_RS = cmd_or_data;
LCD_E_Pulse();
}
void StrConstRamCpy(unsigned char *dest, const code char *source) // Copie le texte de la FLASH ROM vers la RAM.
{
while (*source)*dest ++ = *source ++;
*dest = 0; // Terminateur "0" fin de chaine de caractère.
}
void LCD_Write_String(char *msg) // Variante avec pointeur msg non modifié.
{
int k;
k = 0;
while(*(msg + k) > 0)
{
LCD_Write(DATA, (*(msg + k))); // Data pointée par (msg + k).
k++;
if (k == LCD_COLUMNS) break; // Si k = 16 sortie de la boucle while ...
}
}
void LCD_Write_String_At(char line, char column, char *msg)
{
LCD_Write(CMD, ROW[line]|(column & 0x0F)); // Print message on desired line and desired column.
LCD_Write_String(msg); // OK.
}
void print_float_v11(char *flt, long number, char decimals)
{
if (number < 0)
{
number = - number;
*(flt) = '-';
}
else
{
*(flt) = ' ';
}
if (decimals == 0)
{
*(flt + 1) = ' ';
*(flt + 2) = number / 10000 + '0';
*(flt + 3) = ((number % 10000) / 1000) + '0';
*(flt + 4) = ((number % 1000) / 100) + '0';
*(flt + 5) = ((number % 100) / 10) + '0';
*(flt + 6) = (number % 10) + '0';
*(flt + 7) = ' ';
*(flt + 8) = ' ';
*(flt + 9) = ' ';
*(flt + 10) = ' ';
*(flt + 11) = ' ';
*(flt + 12) = ' ';
}
if (decimals == 1)
{
*(flt + 1) = ' ';
*(flt + 2) = number / 10000 + '0';
*(flt + 3) = ((number % 10000) / 1000) + '0';
*(flt + 4) = ((number % 1000) / 100) + '0';
*(flt + 5) = ((number % 100) / 10) + '0';
*(flt + 6) = ',';
*(flt + 7) = (number % 10) + '0';
*(flt + 8) = ' ';
*(flt + 9) = ' ';
*(flt + 10) = ' ';
*(flt + 11) = ' ';
*(flt + 12) = ' ';
}
if (decimals == 2)
{
*(flt + 1) = ' ';
*(flt + 2) = number / 10000 + '0';
*(flt + 3) = ((number % 10000) / 1000) + '0';
*(flt + 4) = ((number % 1000) / 100) + '0';
*(flt + 5) = ((number % 100) / 10) + '0';;
*(flt + 6) = ',';
*(flt + 7) = (number % 10) + '0';
*(flt + 8) = '0';
*(flt + 9) = ' ';
*(flt + 10) = ' ';
*(flt + 11) = ' ';
*(flt + 12) = ' ';
}
if (decimals > 2)
{
*(flt + 1) = ' ';
*(flt + 2) = number / 10000 + '0';
*(flt + 3) = ((number % 10000) / 1000) + '0';
*(flt + 4) = ((number % 1000) / 100) + '0';
*(flt + 5) = ((number % 100) / 10) + '0';;
*(flt + 6) = ',';
*(flt + 7) = (number % 10) + '0';
*(flt + 8) = '0';
*(flt + 9) = '0';
*(flt + 10) = ' ';
*(flt + 11) = ' ';
*(flt + 12) = ' ';
}
//i = 0; // OK.
i = 2; // OK.
while(flt[i] != ',')
{
if (flt[i] == '0')
{
portc.b3 = 1; // Green LED ON.
flt[i] = ' ';
if (flt[i - 2] == '-')
{
flt[i - 2] = ' ';
flt[i - 1] = '-';
}
if (flt[i + 1] == ',')
{
portc.b2 = 1; // Yellow LED ON.
flt[i] = '0';
}
}
else
{
break;
}
i++;
}
}
void LCD_Init_v4 (void)
{
Delay_ms(15); // LCD power ON initialization time >= 15 mS.
LCD_Write(CMD, 0x30); // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write(CMD, 0x02); // 4 datas bits > Initialization of LCD with nibble method (4 datas bits).
LCD_Write(CMD, 0x28); // 4 datas bits > 2 lines display, 5 × 8 dot character font.
LCD_Write(CMD, 0x0C); // 4 datas bits > Display ON. Cursor OFF.
LCD_Write(CMD, 0x06); // 4 datas bits > Auto increment cursor.
LCD_Write(CMD, 0x01); // 4 datas bits > Clear display.
Delay_ms(1); // Ajustable ... (indispensable, sinon affichage erratique à la mise sous tension)
}
/******************************************************************************/
void main()
{
PORTB = 0; // Initialisation du PORT B à 0.
PORTC = 0; // Initialisation du PORT C à 0.
PORTD = 0; // Initialisation du PORT D à 0.
ANSEL = 0b00001000; // b3 = 1 (ANS3) : sets pin 5 (AN3) as analog input.
ANSELH = 0b00000000;
TRISB = 0b00000000; // PORT B : b0 à b7 configurés en sortie.
TRISC = 0b00000000; // PORT C : b0 à b7 configurés en sortie.
TRISD = 0b00000000; // PORT D : b0 à b7 configurés en sortie.
C1ON_bit = 0; // CMC1CON register > b7 > C1ON bit = 0 > Disable comparator 1.
C2ON_bit = 0; // CMC2CON register > b7 > C1ON bit = 0 > Disable comparator 2.
SCS_bit = 0; // OSCCON register > b0 > SCS bit = 0 > External oscillator (quartz) is used as a clock source.
LCD_Init_v4 (void);
pointeur_de_char = &texte[0]; // pointeur_de_char pointe sur le premier élément du tableau "texte", soit texte[0].
// Autrement dit, pointeur_de_char contient l'adresse (&) de texte[0].
do
{
float adc;
float volt, temp;
char txt[13];
ADC_initialization();
TRISD = 0x00;
while(1)
{
adc = (ADC_read(3)); // Reads analog values.
volt = adc * 4.88281; // Converts it into the voltage.
temp = volt / 10.0; // Gets the temperature values.
temp = temp - 273; // Converts Farenheit to Celcius.
StrConstRamCpy(pointeur_de_char, "Temperature ... "); // OK.
LCD_Write_String_At(0, 0, pointeur_de_char); // OK. Voir dans void LCD_Write_String(char *msg), le while(*(msg + k) > 0).
//print_float_v11(&txt[0], temp, 0);
//print_float_v11(&txt[0], temp, 1);
print_float_v11(&txt[0], temp, 2);
//print_float_v11(&txt[0], temp, 3);
LCD_Write_String_At(1, 0, &txt[0]); // Write txt in 2nd row, starting at 1st digit.
LCD_Write_String_At(1, 12, " °C"); // Write " °C" in 2nd row, starting at 13th digit.
delay_ms(3000);
}
}
while(1);
}