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"); } } } } }
Note that it's very hard to read this code:
ADC->CR &= 0xFFFE; /* Clear STR bit (Start Conversion) */ ADC->CR &= 0x7FFF; /* Clear End of Conversion flag */
It's much better to write:
ADC->CR &= ~0x0001; /* Clear STR bit (Start Conversion) */ ADC->CR &= ~0x8000; /* Clear End of Conversion flag */
Now, the specific bit cleared is visible. And another thing is that the ~ operation will be performed to full integer width. Wahat if you use 0xFFFE to a 32-bit wide register? Then you would also clear the 16 high bits without it being visible to the reader.
Next thing is that it's a good idea to created named constants for your flags.
enum { ADC_CR_STR = 0x0001u, }; ADC->CR &= ~ADC_CR_STR;
Now a reader can see that you are clearing the STR bit of the register, without having to read a comment.
I normally create include files with these additional flags for the different processors I'm using so I would include:
#include "lpc17xx_adc.h" #include "lpc17xx_uart.h" ...
for my projects that are using a processor in the NXP LPC17xx family.
Just wondering how is the display work? For example when we are done with the AD conversion, what next is to display it to the LCD. How can it be done??
As I did mention in a previous post - by having the main loop see flag that there are a new value to print. Then call lcd_print() to emit it. An optimization would be to ignore display update if the new ADC value is the same as what was previously printed.
What i am trying to ask is how to display correctly the AD conversion value to the LCD? As from what i understand, the printing on the LCD is done using char variable encoded in ASCII character. As ADC_value is given as integer value, we would need to convert them into ASCII value, correct me if i am wrong. So the maximum value to be display is 1023. So I am thinking i might need to conver to ASCII before displaying.
by having the main loop see flag that there are a new value to print. Then call lcd_print() to emit it. -> Would appreciate if you could tell me more how to do this?
If you have a number between 0 and 9, you can make it into ASCII by adding '0'.
So if you have a number between 0 and 1023 you could do:
char1 = '0' + (num / 1000); char2 = '0' + ((num / 100) % 10); char3 = '0' + ((num / 10) % 10); char4 = '0' + (num % 10); buf[0] = char1; buf[1] = char2; buf[2] = char3; buf[3] = char4; buf[4] = '\0'; lcd_print(buf);
Or you could use:
sprintf(buf,"%u",num); lcd_print(buf);
There are so many different ways you could select. Google or experiement instead of seeing problems.