Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C Programming for microcontrollers (Joe Pardue, 2005).pdf
Скачиваний:
260
Добавлен:
12.08.2013
Размер:
4.55 Mб
Скачать

Chapter 8: C Pointers and Arrays

Music to my ears. “Play it again Sam.”

We are going to pillage the Butterfly code again and play some tunes to further illustrate the use of pointers and arrays.

More on pointers to arrays

In the original Butterfly code written with the IAR compiler, in sound.c, songs are selected using these definitions:

__flash int __flash

*Songs[]

= { FurElise, Mozart, /*Minuet,

AuldLangSyne,*/ Sirene1,

Sirene2, Whistle, 0};

int __flash *pSong;

//

pointer to the different songs in flash

The __flash is not C, it is a special IAR modifier that allows access to Flash ROM as if it was regular C style RAM. In use:

pSong = Songs[song];

// point to this song

Loads pSong with the pointer to the tune indicated by the song variable. All nice and C like. Unfortunately, the WinAVR compiler isn’t quite as C-like in the way it allows access to Flash ROM. Not that I’m criticizing, I think the WinAVR port of the gcc tools to the AVR platform is a miracle of dedication and technical prowess, not to mention: free. But I won’t mention free. Especially not repeatedly: free, free, free. So this is a miraculous little free compiler (send them some money at: http://www.sourceforge.net/donate.)

The port of the Butterfly code from not-free IAR compiler to the free WinAVR was done by:

Martin Thomas, Kaiserslautern, Germany mthomas@rhrk.uni-kl.de http://www.siwawi.arubi.uni-kl.de/avr_projects/

who did an outstanding job. When you finally learn enough to really evaluate the Butterfly code, you will come to appreciate the intelligence and hard work that this gentleman (my assumption) did for you. Yes, you. And for free. So when you see the way he translated the relatively simple appearing song selection statement, you can agree with his comment below: ‘// looks too complicated’, without getting fussy about it.

189

Chapter 8: C Pointers and Arrays

First look at his version of the definitions:

// pointer-array with pointers to the song arrays

const int *Songs[] PROGMEM = { FurElise, Mozart, Minuet, AuldLangSyne, Sirene1, Sirene2, Whistle, 0};

const int *pSong; // mt point to a ram location (pointer array Songs)

The __flash of the IAR compiler is replaced by the PROGMEM. And the actual use is as follows:

// mt pSong = Songs[song]; // point to

this song

pSong=(int*)pgm_read_word(&Songs[song]);

// looks too

complicated...

Yep, I agree: ‘// looks too complicated', but I have no intention to try to fix it and make it look more C-like. I doubt seriously that I have the time or the skill. In programming microcontrollers in C we sometimes have to dance lightly around ANSI C and use what works.

What the statement says is: we equate a constant integer pointer pointer to a cast of an integer pointer of the function pgm_read_word, which takes as a parameter the address of the song element of the Songs[] array. What we are doing is sending this address to a function that knows how to extract a pointer to Flash RAM. Looks too complicated… but so what, it works.

Setting the frequency

Tones are setup by putting an integer from the song table in the Timer1 Input Capture Register 1, ICR1, which in this case is used to set the counter top value. The values are taken from the Butterfly code and are based on a cpu clock running at 1 MHz. Since we are using a cpu clock of 2 MHz for the USART, adjustments are made that help but do not truly compensate for the difference.

We select a base frequency of 220Hz (the A note) and calculate the frequency for subsequent notes using the notes position on the musical scale following a. For instance, C0 is 3 after A:

190

Chapter 8: C Pointers and Arrays

Tone = 220*2^(NOTE/12)

When NOTE = C0 we get:

Tone = 220*2^(3/12) = 261.6256.

We get the frequency to generate for the tone with:

Timer value = 1Mhz / Tone / 2

For the C0 we would have:

Timer value = 1000000 / 261,6256... / 2 = 1911

So when we want to generate a C0 we set Timer1 to generate a phase/frequency correct PWM with a top value calculated as above. We then compensate for our using a 2Mhz cpu clock by doubling the value using a left bit shift of one position. (In case you didn’t get this earlier, left shifting a byte or integer doubles it if there is headroom. Headroom means the value is less than half the possible value, 256/2 for a byte.)

A few tones from the sound.h table:

#define a

2273

// tone 0

#define xa

2145

// tone 1

#define ax

2145

// tone 1

#define b

2024

// tone

2

#define c0

1911

// tone

3

Setting the tempo

The tempo, in this case, is the length of time we play the tone. The Timer0 calls the Play_Tune function at 10ms intervals. It begins by getting the tempo from the first position of the array and putting it into a Tempo variable. The next time Play_Tune is called, if Tempo is not 0, it decrements the tempo and exits. It continues to do this until the Tempo is 0, when it rereads the tempo and starts over.

191

Chapter 8: C Pointers and Arrays

Setting the duration

The duration and the frequency are paired values in the table. The duration is the length of time that the following tone should be played. Play_Tune gets the duration

and tone from the table and loads them into the Duration variable and the Timer1 top count. It starts the tone and then exits. When called again by Timer0, if the Duration is not 0, Duration is decremented and the function exits leaving the tone playing. When Duration is decremented to 0, Play_Tune gets the next set of values for the Duration and the timer and starts the next tone. If the Duration value read from the table is 0, this indicates that the tune has been played through, so it checks the next byte and if that byte is 1, it starts the tune over, if 0 it ends the tune. Clever, eh?

An example song array – Fur Elise

const int FurElise[] PROGMEM=

{

3,

8,e2, 8,xd2, 8,e2, 8,xd2, 8,e2, 8,b1, 8,d2, 8,c2, 4,a1, 8,p, 8,c1, 8,e1, 8,a1, 4,b1, 8,p, 8,e1, 8,xg1, 8,b1, 4,c2, 8,p, 8,e1, 8,e2, 8,xd2, 8,e2, 8,xd2, 8,e2, 8,b1, 8,d2, 8,c2, 4,a1, 8,p, 8,c1, 8,e1, 8,a1, 4,b1, 8,p, 8,e1, 8,c2, 8,b1, 4,a1,

0, 1 };

Using the Piezo-element to make sound

The piezo-element is the large black square on the back of the Butterfly. It contains a sheet of material that deforms when electricity is applied to it (the piezo electric effect). This deformation can be made at audio frequencies allowing the element to produce sound waves in the air. Our piezo-element is connected to PortB pin 5, which is also the OC1A pin that can be configured as an output for the Timer1 waveform generator. We will configure the Timer1 waveform generator so that it will use PWM to generate tones.

192