How to read Potentiometer and display conversion result

I would to ask how to read the potentiometer(Keil MCBSTR9U) input periodically with a timer interrupt? And also to display the conversion result on the LCD display. Please help. I don't know how to get started.

#include <91x_lib.h>
#include "LCD.h"


extern short AD_last;                     /* Last AD value read in interrupt  */

extern __irq void TIM3_IRQ_Handler(void); /* TIM3 interrupt routine           */
extern __irq void ADC_IRQ_Handler (void); /* ADC  interrupt routine           */


void wait (void)  {                       /* Wait function                    */
  int d;

  d = AD_last;                            /* Read AD_last value               */
  if (d != AD_last)                       /* Make sure that AD interrupt did  */
    d = AD_last;                          /* not interfere with value reading */

  d *= 500;
  d += 50000;                             /* Scale analog value for delay     */
                                          /* lower value -> longer delay      */
  while (d--);                            /* Only to delay for LED flashes    */
}


int main (void) {
  unsigned int i, n;
  unsigned short AD_old, AD_value;
  unsigned char text1[30];

  /* ADC Setup                                                                */
  SCU->GPIOIN[4]  |= 0x01;                /* P4.0 input  - mode 0             */
  SCU->GPIOOUT[4] &= 0xFFFC;              /* P4.0 output - mode 0             */
  GPIO4->DDR      &= 0xFE;                /* P4.0 direction - input           */
  SCU->GPIOANA    |= 0x0001;              /* P4.0 analog mode ON              */

  ADC->CR         |= 0x0002;              /* Set POR bit                      */
  for (n = 0; n < 100000; n ++);          /* Wait > 1 ms  (at 96 MHz)         */

  ADC->CR         &= 0xFFF7;              /* Clear STB bit                    */
  for (n = 0; n < 1500; n ++);            /* Wait > 15 us (at 96 MHz)         */

  ADC->CR         |= 0x0400;              /* Enable end of conversion interupt*/
  ADC->CCR         = 0x0003;              /* AD Conversion, No WDG on Ch 0    */

  SCU->GPIOOUT[7]  = 0x5555;              /* P7.0..7 output - mode 1          */
  GPIO7->DDR       = 0xFF;                /* P7.0..7 Outputs (LED Data)       */

  /* LCD Setup                                                                */
  GPIO8->DDR       = 0xFF;                /* P8.0..7 Outputs (LCD Data)       */
  GPIO9->DDR       = 0x07;                /* P9.0..2 Outputs (LCD Control)    */

  lcd_init();
  lcd_clear();
  lcd_print (" MCB-STR9 DEMO  ");
  set_cursor (0, 0);
  AD_value = ADC->DR0 & 0x03FF;
  sprintf(text1,"ADConversion: %5d",AD_value);
  lcd_print(text1);

  for (i = 0; i < 200; i++) wait();       /* Wait for initial display         */

  /* Configure and enable IRQ for A/D Converter (ADC)                         */
  VIC0->VAiR[15]  = (unsigned int)ADC_IRQ_Handler; /* Setup ADC IRQ Hndl addr */
  VIC0->VCiR[15] |= 0x20;                 /* Enable the vector interrupt      */
  VIC0->VCiR[15] |= 15;                   /* Specify the interrupt number     */
  VIC0->INTER    |= (1<<15);              /* Enable ADC interrupt             */

  /* Configure and enable IRQ for Timer (TIM3)                                */
  VIC0->VAiR[7]   = (unsigned int)TIM3_IRQ_Handler;/* Setup TIM3 IRQ Hndl addr*/
  VIC0->VCiR[7]  |= 0x20;                 /* Enable the vector interrupt      */
  VIC0->VCiR[7]  |= 7;                    /* Specify the interrupt number     */
  VIC0->INTER    |= (1<<7);               /* Enable TIM3 interrupt            */

  /* Timer 3 Configuration (TIM3)                                             */
  TIM3->CNTR      = 0x0000;               /* Setup TIM3 counter register      */
  TIM3->CR2      &= 0xFF00;               /* Clear prescaler value            */
  TIM3->CR2      |= 0x000F;               /* Setup TIM3 prescaler             */
  TIM3->CR2      |= 0x2000;               /* TIM3 timer overflow intrupt en   */
  TIM3->CR1      |= 0x8000;               /* TIM3 counter enable              */

  while (1) {                             /* Loop forever                     */
    for (n = 0x01; n <= 0xFF; n <<= 1) {
      GPIO7->DR[0x3FC] = n;               /* Turn on LED                      */
      wait();                             /* Delay                            */
      AD_value = AD_last;                 /* Read AD_last value               */
      if (AD_value != AD_last)            /* Make sure that AD interrupt did  */
        AD_value = AD_last;               /* not interfere with value reading */
      AD_value /= 13;                     /* Scale to AD_Value to 0 - 78      */
      if (AD_old != AD_value)  {          /* If AD value has changed          */
        set_cursor (0, 1);
        AD_old = AD_value;
        /*for (i = 0; i < 16; i++)  {       // Disp bargraph according to AD
          if (AD_value > 5)  {
            lcd_putchar (0x05);
            AD_value -= 5;
          }  else  {
            lcd_putchar (AD_value);
            AD_value = 0;
          }
        }
      }  */
                if (AD_value >= 0 && AD_value <= 13 ){
            lcd_print("0");
          }
                  else if (AD_value >= 14 && AD_value <= 26) {
                        lcd_print("1");
                  }
                  else if (AD_value >= 27 && AD_value <= 39) {
                        lcd_print("2");
                  }
                  else if (AD_value >= 40 && AD_value <= 52) {
                        lcd_print("3");
                  }
                  else if (AD_value >= 53 && AD_value <= 65)  {
                lcd_print("4");
          }
                  else if (AD_value >= 66 && AD_value <= 78) {
                        lcd_print("5");
                  }
        }
        }
  }
}

Parents
  • Woudlnt' you simply have the timer interrupt start an ADC conversion and then end?
    And the ADC interrupt pick up the ADC conversion result and then end?

    The issue here is that you also want to emit data to the LCD. That is normally not a good thing to do in an inteerrupt because it normally takes very long time to interact with the LCD. So the ADC interrupt would then just have to store the ADC value in a buffer and set a flag that there is a ADC value to emit. And your main loop would see the flag, pick up the value and display it.

    By the way: why so complicated code:

    if (AD_value >= 0 && AD_value <= 13 ){
        lcd_print("0");
    } else if (AD_value >= 14 && AD_value <= 26) {
        lcd_print("1");
    } else if (AD_value >= 27 && AD_value <= 39) {
        lcd_print("2");
    } else if (AD_value >= 40 && AD_value <= 52) {
        lcd_print("3");
    } else if (AD_value >= 53 && AD_value <= 65)  {
        lcd_print("4");
    } else if (AD_value >= 66 && AD_value <= 78) {
        lcd_print("5");
    }
    

    Do you expect the ADC to return negative values? Of course some ADC really can return results in two-complement format or with a sign bit but the majority of ADC only supports measuring a positive input signal.

    Next thing - do you expect your ADC value to be able to have a value > 26 but < 27? Why else do you have two conditions for each range? If there isn't a gap between then, you only need to have a series of "less than" comparisons to bin the ADC value into different bins.

    Next thing - if your bins are always the same size, you don't need to do as above. You can perform an integer division by 14. 13 is smaller than 14, so answer will be zero. 14..27 are less than 2 so but >= 1 so will return value 1.

    By the way - you did notice that your first bin is 14 numbers large, while all other bins are 13 large? A mistake ir really intended?

Reply
  • Woudlnt' you simply have the timer interrupt start an ADC conversion and then end?
    And the ADC interrupt pick up the ADC conversion result and then end?

    The issue here is that you also want to emit data to the LCD. That is normally not a good thing to do in an inteerrupt because it normally takes very long time to interact with the LCD. So the ADC interrupt would then just have to store the ADC value in a buffer and set a flag that there is a ADC value to emit. And your main loop would see the flag, pick up the value and display it.

    By the way: why so complicated code:

    if (AD_value >= 0 && AD_value <= 13 ){
        lcd_print("0");
    } else if (AD_value >= 14 && AD_value <= 26) {
        lcd_print("1");
    } else if (AD_value >= 27 && AD_value <= 39) {
        lcd_print("2");
    } else if (AD_value >= 40 && AD_value <= 52) {
        lcd_print("3");
    } else if (AD_value >= 53 && AD_value <= 65)  {
        lcd_print("4");
    } else if (AD_value >= 66 && AD_value <= 78) {
        lcd_print("5");
    }
    

    Do you expect the ADC to return negative values? Of course some ADC really can return results in two-complement format or with a sign bit but the majority of ADC only supports measuring a positive input signal.

    Next thing - do you expect your ADC value to be able to have a value > 26 but < 27? Why else do you have two conditions for each range? If there isn't a gap between then, you only need to have a series of "less than" comparisons to bin the ADC value into different bins.

    Next thing - if your bins are always the same size, you don't need to do as above. You can perform an integer division by 14. 13 is smaller than 14, so answer will be zero. 14..27 are less than 2 so but >= 1 so will return value 1.

    By the way - you did notice that your first bin is 14 numbers large, while all other bins are 13 large? A mistake ir really intended?

Children
More questions in this forum