Dear Keil users, I'm new here. In BLINKY I want to do the following :
Write the A/D value read from the potentiometer and write it onto the LCD panel
Analogvalue 754
#include <stdio.h> // after reading the analog value set_cursor (0, 0); sprintf(text1,"Analogwert %5d",AD_value); lcd_print (text1);
But I don't know how to read the value from the potentiometer.Any suggestions? Thanks for advance for any help. Adel.
I don't know why, but I somehow get the impression that you haven't spent too much time working with C :)
I can't really tell what you are trying to do. Are you trying to use the ADC value as a programmable delay to control how often you are going to display the ADC value?
Thought not!
Declare a global variable that you set when you get an ADC interrupt, to inform that you have a new ADC value to display.
Let your code wait in a busy loop until the flag gets set. Clear the flag. Pick up the ADC value. Scale the value. Format with sprintf(). Emit to display. Back to wait for new flag from your interrupt.
Not perfect, but quite simple.
Yes, text1 will be missing unless your program contain a declaration for such a variable. If you need a variable with room for up to 30 characters (including terminating zero to end the string), add a variable declaration:
char text1[30];
either before the function, or directly after the first opening brace, before any code lines that tries to do anything.
But a very important thing: Pick up a good book about the C language. You really need one. Or google for any good web sites or free PDF books. But you can't develop your skills without proper documentation of the language.
After you have spent enough time with a good book, or maybe a really good web site, you can then progress by picking up the ISO C standard, since that is the ultimate reference for the language. But to read it, you must first have learned the language and the terminology. And that comes from books or spending significant time browsing web sites.
You will not be able to understand the Keil documentation about processor-specific language extensions if you do not get the background knowledge of the C language.
You have right. I didn't spend enough time with C language. But I'm trying to do is to pickup the value from the potentiometer and convert it to a number(using a library function). I think it must be inside the loop, because I have to update the value while turning the potentiometer.
Adel, No library function is necessary here, we already agreed that the following returns the value of the conversion:
ADC->DR0 & 0x03FF
unless you mean ST's libray for the STR9, of course. Please start by learning C, only then focus on your particular processor and how to utilize its peripherals. Working on this device without some knowledge of how to use it will not bring you anywhere. good luck.
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 */
The above is an attempt to detect if the interrupt has changed a multi-byte value in the middle (or more specifically a value larger than what the processor can natively read in an atomic operation). It is quite common used, but only works if you know that you have enough time to perform the new assign before the next interrupt. An alternative is to use a loop until two samples gives the same value.
d *= 500; d += 50000; /* Scale analog value for delay */ /* lower value -> longer delay */ while (d--); /* Only to delay for LED flashes */
I thought that you intended to display the ADC value as text, but you scale it and then perform a for loop based on the value. Why? Where is the LED that you want to change flash speed for?
AD_last = ADC->DR0 & 0x03FF; set_cursor(0,0); sprintf(text1,"Analogwert %5d",AD_last); lcd_print(text1); }
You did bother with the read-out of the AD_last value (which suddenly seems to be a variable and not a special register for the ADC) when using it as a delay value.
Now, you suddenly seems to read out an ADC value without such control before displaying it on the LCD. What was your intention?
And if AD_last is a normal variable, and not a special register for the ADC (I don't work with your processor) then why the extra assign before scaling and performing the busy-loop?
A good rule when programming: Never add a single line of code without a very specific purpose. You should always be able to defend your decision: Why is it there? What does it solve? What happens if it isn't there?
If you always add source lines because you need them, and not because you can add them, then you will also focus on good solutions, instead of the easiest solution The easiest solution is often a dead end. You get a couple of steps forward before realising that you have to restart.
What I'm trying to do is the following: (speed up the LED and in the same time read the A/D value and convert it to a number) while turning my potentiometer.
the holy code is the following:
#include <stdio.h> #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 */ char text1[10]; /* Declaration a neue variable */ 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 */ AD_last = ADC->DR0 & 0x03FF; /* This is the ADC conversion value */ set_cursor(0,0); /* Set the first line for display*/ sprintf(text1,"Analogwert %5d",AD_last); lcd_print(text1); /* Print the returned Analog value on the first line of diplay */ } int main (void) { unsigned int i, n; unsigned short AD_old, AD_value; /* 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 ("Bonjour Yajour"); set_cursor (0, 1); lcd_print (" http://www.keil.com "); 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; } } } } } }
I had try it and it works (1 warning = argument char* is incompatible with paramter of type const unsigned char*) Maybe it is not the best solution but I'm happy if you can give me a better one. Thanks in advance. Adel.
Look Adel, this is not the way to go. Seriously, you *MUST* know what you're doing before you start with thi stuff - the fact that your code "works" means nothing at all. it does not make any sense - at least not the ADC related parts. you are asking the ADC to interrupt the processor when the conversion is ready, yet you poll the value in the wait function :-0 ! so I guess you can shutdown the "conversion ended" interrupt all together, not? Please please please sit down, read and learn first... Good luck again
Is this whole forum full of people just taking the pi*s, getting people to spend good time replying to complete idiots?
Listen Dodgey Dave ***,
First of all you have to respect the terms of use in the forum and don't say to anyone an iodot. Second, this a public forum and all people could post their question regardless of their programming level. I don't see in this forum any rubric for low or advanced levels. And if you're not able to respond to questions let your comemnts in your home. So respect yourself next time.
So, have you performed the normal routine of eliminating possible error sources?
Have you verified that the potentiometer can generate the full range of voltages that the ADC can measure?
Have you verified that the ADC voltage reference is correct?
Have you verified that the binary value you read from the ADC can take any value between 0 and 0x3ff, i.e. between 0 and 1023?
Have you verified that your sprintf - if given a value of 1023 - will produce a correct text string?
Have you verified that said string will be corerctly sent to the display?
Performing these steps should give a good indication exactly what problem you have - and how/if you can fix it.