This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430F5529: ADC measures on LCD 1602

Part Number: MSP430F5529
Other Parts Discussed in Thread: PCF8574

Tool/software: Code Composer Studio

Hi! I have a problem related to the ADC. My purpose is to take some measures of incident light with 2 LDRs and showing its values with two ADC channels. Also i would like show the value measured on a LCD 1602 to make sure i'm doing it in right. My issue is not related to displaying the values as i think, cause i made before an exercise to display an array of characters like the typpical 'Hellow World' and it worked. So my main problem is related to the extra of measuring with the ADC. I have some doubts that i'm doing well the steps for CONSEQ_3 mode in ADC. I paste my code and if anyone see anything wrong, please let me know! Thnks a lot btw. 

[For clarity, TI moved the source code to an attachment]

adc_measures_on_LCD.c
Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <msp430.h>
#include <stdint.h>
#include <stdio.h>
// Variables para la LCD:
typedef unsigned char byte;
#define Enable_LCD 0x04
#define iluminacion_LCD 0x08
#define comando_LCD 0x00
#define dato_LCD 0x01
#define LCD_PCF8574_ADDRESS 0x27 // Slave address poniendo A0,A1,A2 = 1
// Variables para el ADC:
volatile uint8_t buffer_lleno = 0;
uint16_t valor_promedio_A0 = 0; // Variable that stores average value of A0
uint16_t valor_promedio_A1 = 0; // Variable that stores average value of A1
uint8_t *PTxData; // Pointer to TX
uint8_t TXByteCtr; // Counter of bytes send
uint16_t volatile contador_milisegundos;
void Inicializacion_Relojes(void)
{
__bis_SR_register(SCG0); // Disable the FLL control loop
UCSCTL0 = 0x0000;
UCSCTL1 = DCORSEL_5;
UCSCTL2 = FLLD_0 | 487;
// (N + 1) * (FLLRef/n) = Fdcomsp430
// (487 + 1) * (32768/1) = 16MHz
UCSCTL3 = 0; // FLL SELREF = XT1CLK y divisor de FLL = 1 (FLLREFDIV = FLLREFCLK/1)
UCSCTL4 |= SELA_0 | SELS_4 | SELM_4; // Tomamos ACLK = XT1CLK (Cuarzo externo de 2^15 bits); SMCLK = MCLK = DCOCLKDIV (DCO interno de 16 MHz)
// UCSCTL5 |= DIVA_0 | DIVS_0;
__bic_SR_register(SCG0); // Enable the FLL control loop
}
void USCIB1_init()
{
P4SEL |= BIT2 | BIT1; // P4.1 --> UCB1SDA
// P4.2 --> UCB1SCL
UCB1CTL1 |= UCSWRST;
UCB1CTL0 |= (UCMST | UCMODE_3 | UCSYNC); // UCMST: Master; UCMODE_3: Modulo USCI como I2C; UCSYNC: Modo Sincrono
UCB1CTL1 |= (UCSSEL_2 | UCSWRST); // UCSSEL_2: SMCLK; UCSWRST: Usci sigue en estado Reset
UCB1BR0 = 160; // fSCL = SMCLK(16MHz)/160 = 100kHz
UCB1BR1 = 0;
UCB1CTL1 &= ~UCSWRST;
UCB1IE |= UCTXIE;
}
void delay_ms(uint16_t tiempo_milisegundos)
{
contador_milisegundos = 0;
TA1CTL |= MC_1; UP MODE
TA1CCTL0 |= CCIE;
while(contador_milisegundos < tiempo_milisegundos);
TA1CTL |= MC_0; // STOP MODE
}
void init_TimerA1_ms(void)
{ // Timer for counting every ms for delay_ms
TA1CCR0 = 16000-1;
TA1CTL |= TASSEL_2 | MC_0; // Reloj SMCLK, Frecuencia: 16 MHz. Modo Stop.
}
// Funcion para configurar el ADC:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hello user5993700,

    Let me take a look and see what I can discover.

  • Ok. Thanks a lot!

  • What is your symptom exactly? What appears on the screen?

    ----------------

    > char datos_A0[4], datos_A1[4];

    > sprintf(datos_A0,"valor ADC_A0=%d",valor_promedio_A0);
    > sprintf(datos_A1,"valor ADC_A1=%d",valor_promedio_A1);

    This is trouble, since the resulting string is longer than your buffer array(s). You should (a) use snprintf and (b) make your arrays longer.

    ----------------

    ADC12CTL0 |= ADC12ENC; // enable ADC

    The ISR disables the ADC, and this re-enables it. But that leaves it waiting for a trigger, so you should set ADC12SC as well. [Ref User Guide (SLAU208Q) Fig 28-10. 

    Also, clearing ENC doesn't stop the ADC immediately [Ref UG Sec 28,2.7.6]. So when you do this the ADC may or may not still be running. I suggest something like:

     while (ADC12CTL1 & ADC12BUSY) /*EMPTY*/; // Let the ADC wind down
     index  = 0; // Start over
     ADC12CTL0 |= ADC12ENC | ADC12SC;  // Start the ADC again
    
    

    [Edit: Fixed the formatting a little]

  • My LCD displays the message 'Hello Worlddddddddddd' correctly, then clears the screen as i told with the function 'borrar pantalla' after applying the delay of 1000 ms and then it only appears the cursor blinking without any ADC value appearing on the screen. 

    Ok. A few questions about what you suggest. First of all what is the difference between using sprintf and snprintf? Adn why you warn me about using snprintf btw? 

    Also, i put what you told me in that order cause i don't see clearly where all it goes in my code, so i suposed it by thinking what everything does but i could be doing in the wrong way. Is everything correct then?

    I also paste you my LCD functions related to printing characters on the display since i want to make the screen shifting all the way on the left always, so maybe i could put a command like 'Return to Home' after displaying all the message of 'Hello Worlddddddd' to make sure that it doesn't stop in lddddddddd as it does now. Thanks btw!

    void lcd_setCursor(byte fila, byte columna)
    {
    byte address;

    if (fila == 0){ // first row
    address = 0;
    }
    else address = 0x40; // Second row

    address |= columna; // Para tener 0x00 + Columna (Fila1)
    // Para tener 0x40 + Columna (Fila2)

    lcd_send_byte_data(0x80 | address); // Set DDRAM Address
    delay_ms(2);
    }

    void lcd_print(char *string, uint8_t fila, uint8_t columna)
    {
    uint8_t tamaño;
    lcd_setCursor(fila,columna);

    while(*string != '\0')
    {
    lcd_send_byte_data(*string++); // write the character on the LCD
    tamaño++;
    if(tamaño > (16-columna))
    {
    lcd_send_byte_cmd(0x18); // Display shift to left
    delay_ms(300); // delay to see how characters are shifted
    }
    }
    delay_ms(2);
    }

    void borrar_pantalla(void)
    {
    lcd_send_byte_cmd(0x01); // clear display
    delay_ms(2);
    lcd_send_byte_cmd(0x02); // Return Home
    delay_ms(2);
    }

    void main(void)
    {
    char datos_A0[10], datos_A1[10]; // I put size of 10 elements to make sure that i can put all the characters, so i have supposed a bigger size than what i could expect to have
    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
    Inicializacion_Relojes();
    USCIB1_init();
    init_TimerA1_ms();
    __enable_interrupt();
    init_LCD_PCF8574();
    borrar_pantalla(); // delete anything that could appear in the display, for clearing it
    lcd_print("Hello Worlddddddddddddddd!",0,0); // Message to show that LCD display seems to work fine
    delay_ms(1000);
    borrar_pantalla();
    ConfiguracionADC();
    delay_ms(300); // wait for stabilize voltage reference
    ADC12CTL0 |= ADC12SC; // ADC12SC: begins the conversion
    __bis_SR_register(LPM0_bits + GIE);
    while(1){
    while (ADC12CTL1 & ADC12BUSY) /*EMPTY*/; // Let the ADC wind down
    if (buffer_lleno == 1){
    snprintf(datos_A0,"valor ADC_A0=%d",valor_promedio_A0);
    snprintf(datos_A1,"valor ADC_A1=%d",valor_promedio_A1);
    lcd_print(datos_A0,0,4); // In row 0 of the LCD i put the A1 average value
    lcd_print(datos_A1,1,4); // In row 1 of the LCD i put the A1 average value
    valor_promedio_A0 = 0; // Reset value of A0
    valor_promedio_A1 = 0; // Reset value of A1
    buffer_lleno = 0;
    ADC12CTL0 |= ADC12ENC | ADC12SC; // Start the ADC again
    }
    }
    }

    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR (void)
    {
    static unsigned int index = 0;
    switch(__even_in_range(ADC12IV,34))
    {
    case 0: break; // Vector 0: No interrupt
    case 2: break; // Vector 2: ADC overflow
    case 4: break; // Vector 4: ADC timing overflow
    case 6: break;
    case 8: // Vector 8: ADC12IFG1
    valor_promedio_A0 += ADC12MEM0;
    valor_promedio_A1 += ADC12MEM1;
    index++;
    if (index == 8){
    buffer_lleno = 1;
    valor_promedio_A0 >>= 3; // To divide by 8 to take the average value cause i had measured 8 samples.
    valor_promedio_A1 >>= 3;
    index = 0;
    ADC12CTL0 &= ~ADC12ENC; // Deshabilitamos el ADC
    }
    break;
    case 10: break; // Vector 10: ADC12IFG2
    case 12: break; // Vector 12: ADC12IFG3
    case 14: break; // Vector 14: ADC12IFG4
    case 16: break; // Vector 16: ADC12IFG5
    case 18: break; // Vector 18: ADC12IFG6
    case 20: break; // Vector 20: ADC12IFG7
    case 22: break; // Vector 22: ADC12IFG8
    case 24: break; // Vector 24: ADC12IFG9
    case 26: break; // Vector 26: ADC12IFG10
    case 28: break; // Vector 28: ADC12IFG11
    case 30: break; // Vector 30: ADC12IFG12
    case 32: break; // Vector 32: ADC12IFG13
    case 34: break; // Vector 34: ADC12IFG14
    default: break;
    }
    }

  • > char datos_A0[10], datos_A1[10];

    > snprintf(datos_A0,"valor ADC_A0=%d",valor_promedio_A0);

    You can't fit 17 bytes of string into a 10-byte (or 4-byte) array. If you ask it to, sprintf will keep writing past the end of the array, and will overwrite something unrelated. Using snprintf , you can avoid this -- your string won't look right, but at least it won't cause trouble elsewhere.

    The unknown damage that can be caused by an array overrun is significant enough that further diagnosis isn't really useful until it's fixed.

    I'm pretty sure that snprintf() call  won't compile. Google "snprintf" (top two results) to read about snprintf.

    ---

    I suggested those 3 lines of code to replace the 1 line I cited. What you have there will probably work, but you may see some artifacts, depending on how long the ADC takes to stop.

  • Thanks for your time and all your repplies. Really help! I gotta say i finally fixed the program and it worked. 

**Attention** This is a public forum