📄 asuro 020.c
字号:
// ================================================================================//
//
// Program : Asuro 020, Build 001, Asuro playing music.c
// Release date : 2005-02-19
// Author : Henk van Winkoop
//
// Build : 001, 2005-02-19, original release
// Build : 002, 2005-02-20
// - some bugs released
// - high octave playing modes added
// - keyboard 'q' and '1' keys changed/added
//
// ================================================================================
/*
Asuro starts playing song 'Jesus bleibt mein Freude' from Bach.
It's playing the song with it's engines!
Frontswitches (No. 1 is front left near the dark infrared led.)
No. 1. Playing song (low pitch), stop, playing higher pitch, stop ,playing lower pitch, stop, repeat...
No. 2. Bottom left/right tracksensor sensors control pitch of left/right engine/speakers, stop, repeat...
No. 3. Left/right wheel distance sensors control pitch of left/right engine/speakers, stop, repeat...
No. 4. Playing synthesizer sounds (low pitch), stop, playing higher pitch, stop, repeat...
No. 5. Playing like a siren (low pitch), stop, playing high itch, stop, repeat...
No. 6. Using Hyperterminal computer keyboard keys like playing a keyboard using keys
a,s,e,d,r,f,g,h,u,j,i,k,l,p,;,[,',\,
'1' toggles between low/high pitch
'q' toggles right engine of in low pitch mode (due to high current drawn from both engines Asuro may hang)
If No. 6. hangs itself then press switch 6 twice (stop/start) and then first press 'q' key before starting playing.
How does this program work?
The sound that Asuro produces is generated by it's engines. The engines are driving
alternating forward and reverse at the speed of sound frequencies.
The engines stator will move according this frequency and produce soft sounds.
The Atmega8L microcontroller contains 3 independent timer/counters. Timer0 is used
for the left engine producing sounds. Timer1 does this for the right engine. Timer2
controls the length of produced sounds. On each entry of timer0 and timer1 interrupt
handlers the forward/backward direction off both engines is toggled.
Timer0 is an 8-bit timer that only is capable of counting up.
Timer1 is an 16-bit timer that is capable of counting up and counting down.
Timer1 is an 8-bit timer that is capable of counting up and counting down.
For sound generation an 8-bit timer is sufficient.
Timer0 does not have any capability for triggering an event at a certain count.
So timer0 is used with it's overflow interrupt (when counting from oxFF to 0x00) while
the interrupt handler reloads the requested timer0 counter value from a global variable.
So a higher reload value will produce a higher sound pitch.
To make timer1 react equal to timer0 its WGM mode is set to 5. The TOP of timer1 now is
automatically set to 0xFF and timer1 will generate an interrupt on each overflow.
Both timer0 and timer1 are used with prescaler /64. This makes each counterstep last
2.048/256=8us making counter frequency range from 448Hz up to 125KHz. As the engines are toggled
at each interrupt the real sound pitch frequency must be divided by two. This makes the
usable frequencies range from 224Hz to 63KHz.
Timer2 is set to WGM mode 0 that makes it's TOP at 0xFF and the overflow interrupt set
at MAX which is also 0xFF. Timer2 reload value is not used. Timer2 just runs free and
generates an interrupt at each 256 timer cycles. As timer2 prescaler is set to 1024 it's
frequency ranges from 30,52Hz up to 7.813Hz. As no reload is used timer2 interrupts occur
at a frequency of 30,52Hz or each 32.768us.
A statemachine is used for handling the 6 software operation modes. Operation modes are
executed by pressing the corresponding Asuro front switch.
Mode
1. playing song 'Jesus bleibt mein Freude' with random toggling leds
2. tracksensors are controlling the corresponding engine sound pitch
3. odometrie sensors are controlling the corresponding engine sound pitch
4. two random generators generate random sound pitches with random toggling leds (startrek sounds)
5. a software upcounter and a software downconter are controlling engines producing up/down going sounds
6. received infrared codes from hyperterminal keyboard, control both engines like a music keyboard
'q' is used to toggle pitch-range and both engines produce a sound differencing 1 reload value so
a nice interfering sound is produced.
Controlling both engines in mode 6 may cause the power supply to drop to 3V which sometimes stops/hangs
the program. Use 'q' to switch to higher pitch range which uses much less current. Also the low range
sound need that much current that hyperterminal keys will not be received as long as the current
tone is playing. Each tone plays about half a second. The high range does not block receving
hyperterminal keys while a tone is being played.
Again: a statemachine is used for handling the 6 software operation modes
The statemachine runs continuously in the main() function. A statemachine state change is
initiated by a frontswitch press.
Each Asuro frontswitch keypress generates an interrupt. The interrupt handler then starts the
ad-conversion for measuring the pressed key voltage. The ad-conversion when ready generates
also an interrupt. In the ad-converter intrrupt handler the pressed keys are analysed.
Each pressed key selects a unique statemachine state.
Overall timing functions such as tone-duration are handled inside the timer2 overflow interrupt
handler. Many states have their own specific interrupts-counting compare value at which compare
they handle their specific tasks.
ENGINES
To make the engine produce a sound, the speed-control input must be set high and the both
forward/reverse connections must be toggling between high/low and low/high.
To stop the engines from playing the corresponding overflow interrupt must be disabled.
But this leaves the engines forward/reverse in a high/low or low/high state which then
(after an interrupt disable) will drive the engine forward or reverse. So beside disabling
the interrupt, both forward/revers connections of the seected engine must be set to high/high.
An alternative way would be to just disable the engine by setting the speed-control connection
to low and keep the interrupts running. But this is no nice programming as why leave interrupts
running if they are not needed. The timer0/timer1 interrup handlers, if enabled will automatically
start toggling the forward/reverse connections so when enabling a timer0/timer1 overflow interrupt
there is no need to somehow enable the engines by handling their forward/reverse connections.
Just enabling the interrupts will start the sound generation.
SWITCHES
The switch function analyses the pressed key related mode (statemachine state). A same mode will stop
the execution of the current mode. A new mode will stop the current running mode. A new mode will
be activated if no mode is active at the moment.
USART
The usart should be disabled if not used because else the usart will keep receiving new infrared
characters and will immediately start interrupt handling as soon as the usart is enabled and its
interrupt-enable is activated.
SOUND PITCHES
A frequency of 440Hz ('A') corresponds to a period of 2273us.
A toggling timer interrupt-handler must generate a delay of 2273/2=1137us to generate a sound pitch
of 440Hz. 1137us divided by 8us timer step value (or 2273/16) makes decimal 142 or hex 0x8E. To make
a counter count 0x8E steps it must be (re)loaded by 0x0100 - 0x8E = 0x72.
Due to a misjudgement all reload values are decremented by 1. So 0x72 becomes 0x71.
The generated sounds occupy the 220Hz octave and the 440Hz octave from 'C' to 'C'.
So totally 25 tones may be produced.
tone|white|black| us|/16|hex|^hex|+1 (range 011)
4545 > unused calculated data
4290 > unused calculated data
4050 253 FD 02 03 <------ lowest pitch used ------
C 3822 239 EF 10 11
3608 226 E2 1D 1E
D 3405 213 D5 2A 2B
3214 201 C9 36 37
E 3034 190 BE 41 42
F 2863 179 B3 4C 4D
2703 169 A9 56 57
G 2551 159 9F 60 61
2408 151 97 68 69
A 440 2273 142 8E 71 72 <<<======= 440 Hz ========
466 2145 134 86 79 7A
B 494 2025 127 7f 80 81
C 523 1911 120 78 87 88
554 1804 113 71 8E 8F
D 587 1703 106 6A 95 96
622 1607 100 64 9B 9C
E 659 1517 95 5F A0 A1
F 698 1432 90 5A A5 A6
740 1351 84 54 AB AC
G 784 1276 80 50 AF B0
831 1204 75 4B B4 B5
A 880 1136 71 47 B8 B9
932 1073 67 43 BC BD
B 988 1012 63 3F C0 C1
C 1047 956 60 3C C3 C4 <------ lowest pitch used ------
1109 902 \
1175 851 |
1245 804 |
1319 758 |
1397 716 |
1480 676 |
1568 638 |
1661 602 |
1760 568 |
536 > unused calculated data
506 |
478 |
451 |
427 |
402 |
379 |
358 |
338 |
318 |
301 /
Remember:
- both Asuro engines have a 'upper' direction control and a 'lower' speed control
- to make Asuro produce sounds with it's engines, it's engines must be toggled
forward/reverse at the pitch of the sound
- to make the engines toggle, the speed-control input of the engines must be
continuous enabled
- the speed-control signals are directly connected to the compare outputs of
the microcontroller
- to avoid that the microcontroller is switching the speed-control outputs only
the timer/counter1 output modes 0 (from 0-3) may be used
- to generate variable sound pitches the timer/counter TOP value must be adjustable
- to generate two different sound pitches for each engine, two timers are needed
Some idea's
- It would be more nice if engines start/stop is done by enabling/disabling prescalers.
- timer0 has lowest timers priority and should be used in stead off timer2
*/
//--------------------------------------------------------------------------------
// INCLUDES
//--------------------------------------------------------------------------------
#include "hvwdefines.h"
#include <stdlib.h>
//--------------------------------------------------------------------------------
// DEFINES
//--------------------------------------------------------------------------------
// not-false = true (!0x00=0x01) and not-true is false (!0x01=0x00)
#define bool unsigned char
#define false 0x00
#define true 0x01
#define NUMOF_MUSIC_TONES 26
#define NUMOF_TIMER2_INTERRUPTS 100
#define NUMOF_TIMER2_KEYBOARD_INTERRUPTS 80
#define NUMOF_TIMER2_SYNTHESIZER1_INTERRUPTS 20
#define NUMOF_TIMER2_SYNTHESIZER2_INTERRUPTS 10
#define NUMOF_SONG1_TONES 100
#define NUMOF_SONG2_TONES 100
#define PLAY_MODE_NONE 0
#define PLAY_MODE_SONG_PLAYING_INIT 1
#define PLAY_MODE_SONG_PLAYING 2
#define PLAY_MODE_KEYBOARD_PLAYING_INIT 3
#define PLAY_MODE_KEYBOARD_PLAYING 4
#define PLAY_MODE_TRACK_SENSORS_INIT 5
#define PLAY_MODE_TRACK_SENSORS 6
#define PLAY_MODE_ODO_SENSORS_INIT 7
#define PLAY_MODE_ODO_SENSORS 8
#define PLAY_MODE_SYNTHESIZER1_INIT 9
#define PLAY_MODE_SYNTHESIZER1 10
#define PLAY_MODE_SYNTHESIZER2_INIT 11
#define PLAY_MODE_SYNTHESIZER2 12
#define PLAY_MODE_ALL_OFF_INIT 13
#define PLAY_MODE_ALL_OFF 14
#define KEY_NONE 0x00
#define KEY1 0x20
#define KEY2 0x10
#define KEY3 0x08
#define KEY4 0x04
#define KEY5 0x02
#define KEY6 0x01
//--------------------------------------------------------------------------------
// FUNCTION PROTOTYPES
//--------------------------------------------------------------------------------
void vDisableAllInterruptsExceptSwitchesInterrupt(void);
void vInitAllPortsAsInputsAndOutputs(void);
void vInitTimerCounter0(void);
void vInitTimerCounter1(void);
void vInitTimerCounter2(void);
void vDelayXMilliSeconds(int iDelMilSec);
void vInitMusicPlaying(void);
void vInitSwitchesForUsingWithInterrupts(void);
void vShowHexNumberBySystemLed(unsigned char ucErrNum);
void vInitUsartRx2400B8N1UsingRxInterrupt(void);
void vInitEnginesForMusicPlayingWithoutStart(void);
void vAllLedsOff(void);
void vToggleAllLedsAtRandom(void);
void vToggleSoundPitchEightOctaves(void);
void vResetAllTimersPrescalers(void);
//--------------------------------------------------------------------------------
// GLOBALS
//--------------------------------------------------------------------------------
unsigned char gucTm0IntCnt;
unsigned char gucTm0CurRldVal;
unsigned char gucTm0NewRldVal;
unsigned char gucTm1IntCnt;
unsigned char gucTm1CurRldVal;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -