📄 rp6controllib.c
字号:
* Example:
*
* // Write a hexadecimal number to the LCD:
* writeInteger(0xAACC,16);
* // Instead of 16 you can also write "HEX" as this is defined in the
* // RP6RobotBaseLib.h :
* writeInteger(0xAACC, HEX);
* // Other Formats:
* writeInteger(1024,DEC); // Decimal
* writeInteger(511,OCT); // Ocal
* writeInteger(0b11010111,BIN); // Binary
*/
void writeIntegerLCD(int16_t number, uint8_t base)
{
itoa(number, &lcd_tmp_buffer[0], base);
writeStringLCD(&lcd_tmp_buffer[0]);
}
/**
* Same as writeInteger, but with defined length.
* This means this routine will add leading zeros to the number if length is
* larger than the actual value or cut the upper digits if length is smaller
* than the actual value.
*
* Example:
*
* // Write a hexadecimal number to the LCD:
* writeIntegerLength(0xAACC, 16, 8);
* // Instead of 16 you can also write "HEX" as this is defined in the
* // RP6ControlLib.h :
* writeIntegerLength(0xAACC, HEX, 8);
* // Other Formats:
* writeIntegerLength(1024,DEC,6); // Decimal
* writeIntegerLength(511,OCT,4); // Ocal
* writeIntegerLength(0b11010111,BIN,8); // Binary
*/
void writeIntegerLengthLCD(int16_t number, uint8_t base, uint8_t length)
{
char buffer[17];
itoa(number, &buffer[0], base);
int8_t cnt = length - strlen(buffer);
if(cnt > 0) {
for(; cnt > 0; cnt--, writeCharLCD('0'));
writeStringLCD(&buffer[0]);
}
else
writeStringLengthLCD(&buffer[0],length,-cnt);
}
/**
* This function is useful for displaying text screens on the LCD.
* It clears the whole LCD and writes the two Strings to line 1 and
* line 2.
*/
void _showScreenLCD_P(const char *line1, const char *line2)
{
clearLCD();
writeNStringLCD_P(line1);
setCursorPosLCD(1, 0);
writeNStringLCD_P(line2);
}
/**
* Sets the cursor position on LCD.
*/
void setCursorPosLCD(uint8_t line, uint8_t pos)
{
pos |= 128;
if(line==1) pos += 0x40;
writeLCDCommand(pos);
}
/**
* Clears some characters after the given position.
*/
void clearPosLCD(uint8_t line, uint8_t pos, uint8_t length)
{
setCursorPosLCD(line,pos);
while(length--)
writeCharLCD(' ');
}
/*****************************************************************************/
// Keypad:
/**
* Checks which key is pressed - returns the key number,
* or 0, if no key is pressed.
* Maybe you need to adjust these values because of variations
* in the resitors of the keypad!
*
*/
uint8_t getPressedKeyNumber(void)
{
uint16_t keys;
keys = readADC(ADC_KEYPAD);
if(keys < 1020) {
nop();
nop();
nop();
keys += readADC(ADC_KEYPAD);
keys >>= 1;
}
if(keys < 50)
return 1;
if(keys < 580)
return 2;
if(keys < 700)
return 3;
if(keys < 790)
return 4;
if(keys < 830)
return 5;
return 0;
}
/**
* This function has to be called frequently out of
* the main loop and checks if a button is pressed! It only returns
* the key number a single time, DIRECTLY when the button is pressed.
*
* This is useful for non-blocking keyboard check in the
* main loop. You don't need something like
* "while(getPressedKeyNumber());" to wait for the button
* to be released again!
*/
uint8_t checkPressedKeyEvent(void)
{
static uint8_t pressed_key = 0;
if(pressed_key) {
if(!getPressedKeyNumber())
pressed_key = 0;
}
else {
pressed_key = getPressedKeyNumber();
if(pressed_key)
return pressed_key;
}
return 0;
}
/**
* This function has to be called frequently out of
* the main loop and checks if a button is pressed AND
* released. It only returns the key number a single time,
* AFTER the button has been released.
*
* This is useful for non-blocking keyboard check in the
* main loop. You don't need something like
* "while(getPressedKeyNumber());" to wait for the button
* to be released again!
*/
uint8_t checkReleasedKeyEvent(void)
{
static uint8_t released_key = 0;
if(released_key) {
if(!getPressedKeyNumber()) {
uint8_t tmp = released_key;
released_key = 0;
return tmp;
}
}
else
released_key = getPressedKeyNumber();
return 0;
}
/*****************************************************************************/
// Microphone:
/**
* This function discharges the Capacitor of the peak detection circuit
* used for the Microphone. This is required to remove any previous
* charge from the capacitor.
*/
void dischargePeakDetector(void)
{
DDRA |= MIC;
PORTA &= ~MIC;
mSleep(1);
DDRA &= ~MIC;
}
/**
* Reads the Microphone peak detector and discharges it afterwards.
*
*/
uint16_t getMicrophonePeak(void)
{
uint16_t tmp;
tmp = readADC(ADC_MIC);
if(tmp > 4)
dischargePeakDetector();
return tmp;
}
/*****************************************************************************/
// Delays, Stopwatches and Beeper:
// ---------------------
// Internal status bits
volatile union {
uint8_t byte;
struct {
unsigned beep:1;
unsigned unused:7;
};
} controlStatus;
volatile stopwatches_t stopwatches;
volatile uint8_t delay_timer;
volatile uint8_t ms_timer;
volatile uint16_t sound_timer;
volatile uint16_t timer; // You can use this timer for everything you like!
/**
* Timer 0 Compare ISR - This timer is used for various
* timing stuff: The delay timer for blocking delays,
* "Stopwatches" for non-blocking delays and the timing of
* the sound generation with timer2...
*
* By default, it runs at 10kHz which means this ISR is called
* every ~100祍! This is nice for timing stuff!
*/
ISR (TIMER0_COMP_vect)
{
// 16bit timer (100祍 resolution)
timer++;
// Blocking delay (100祍):
delay_timer++;
// All 1ms based timing stuff
if(ms_timer++ >= 10) { // 10 * 100祍 = 1ms
// 16bit Stopwatches:
if(stopwatches.watches & STOPWATCH1)
stopwatches.watch1++;
if(stopwatches.watches & STOPWATCH2)
stopwatches.watch2++;
if(stopwatches.watches & STOPWATCH3)
stopwatches.watch3++;
if(stopwatches.watches & STOPWATCH4)
stopwatches.watch4++;
if(stopwatches.watches & STOPWATCH5)
stopwatches.watch5++;
if(stopwatches.watches & STOPWATCH6)
stopwatches.watch6++;
if(stopwatches.watches & STOPWATCH7)
stopwatches.watch7++;
if(stopwatches.watches & STOPWATCH8)
stopwatches.watch8++;
// Sound generation timing:
if(controlStatus.beep) {
if(sound_timer < 1) { // sound_timer * 1ms
TCCR2 = 0;
controlStatus.beep = false;
}
else
sound_timer--;
}
ms_timer = 0;
}
}
/**
* You can use this function to make the beeper beep ;)
* But this function should not be used as it does not
* generate a delay for the sound and a delay between
* two sounds. Better is to use the "sound" macro, which
* uses this function and adds the required delays.
*
* "sound(pitch,time,delay)"
*
* 0 = lowest frequency
* 255 = highest frequency
*
* Example:
* sound(150,50,25);
* sound(200,50,25);
*
* Of course the function "beep" is nice to generate
* sounds when you need to do other things at the same
* time...
*/
void beep(uint8_t pitch, uint16_t time)
{
controlStatus.beep = true;
sound_timer = time;
OCR2 = 255-pitch;
TCCR2 = (1 << WGM21) | (1 << COM20) | (1 << CS22) | (1 << CS21);
}
/**
* This function has no timing stuff, but otherwise
* it has the same effect as "beep". It only sets the pitch
* and this can be used to generate tone sequences which
* would sound bad if the beeper turns of for a very short time
* in between - such as alarm tones or special melodies etc.
*/
void setBeeperPitch(uint8_t pitch)
{
controlStatus.beep = false;
OCR2 = 255-pitch;
if(pitch)
TCCR2 = (1 << WGM21) | (1 << COM20) | (1 << CS22) | (1 << CS21);
else
TCCR2 = 0;
}
/**
* Delay with the help of the 10kHz timer.
* sleep(10) delays for *about* 1ms! Not exaclty, as we do not use assembly routines
* anywhere in this library!
*
* This is a blocking routine, which means that the processor
* will loop in this routine and (except for interrupts) the
* normal program flow is stopped!
* Thus you should use the Stopwatch functions wherever you can!
*
* Example:
* sleep(1); // delay 1 * 100us = 100us = 0.1ms
* sleep(10); // delay 10 * 100us = 1000us = 1ms
* sleep(100); // delay 100 * 100us = 10000us = 10ms
* // The maximum delay is:
* sleep(255); // delay 255 * 100us = 25500us = 25.5ms
*/
void sleep(uint8_t time)
{
delay_timer = 0;
while (delay_timer <= time+1);
}
/**
* The same as sleep() but this delays for time*1ms.
*
* Example:
* mSleep(100); // delay 100 * 1ms = 100ms = 0.1s
* mSleep(1000); // delay 1000 * 1ms = 1000ms = 1s
*
*/
void mSleep(uint16_t time)
{
while (time--) sleep(10);
}
/**
* Delay a number of instruction cycles.
* No exact delay function! And interrupts can still occur and
* add a lot of extra cycles.
* This function only guarantees to delay for a MINIMAL number
* of cycles!
*
* Example:
* delayCycles(1000); // Delays for *about* 1000 instruction cycles
*/
void delayCycles(uint16_t dly)
{
while(dly--) nop();
}
/*****************************************************************************/
// Initialisation:
/**
* Initialize the Controller - ALWAYS CALL THIS FIRST!
* The Processor will not work correctly otherwise.
* (If you don't implement your own init routine...)
*
* Example:
*
* int main(void)
* {
* initRP6Control(); // CALL THIS FIRST!
*
* // ... your application code
*
* while(true);
* return 0;
* }
*
*/
void initRP6Control(void)
{
portInit(); // Setup port directions and initial values.
// This is the most important step!
cli(); // Disable global interrupts.
// UART:
UBRRH = UBRR_BAUD_LOW >> 8; // Setup UART: Baud is Low Speed
UBRRL = (uint8_t) UBRR_BAUD_LOW;
UCSRA = 0x00;
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
// Initialize ADC:
ADMUX = 0; //external reference
ADCSRA = (0<<ADIE) | (0<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADIF);
SFIOR = 0;
// Initialize External interrupts - all disabled:
MCUCR = (1 << ISC11) | (1 << ISC10) | (1 << ISC01) | (1 << ISC00);
GICR = (0 << INT2) | (0 << INT1) | (0 << INT0);
MCUCSR = (0 << ISC2);
// 10kHz Timer 0:
TCCR0 = (0 << WGM00)
| (1 << WGM01)
| (0 << COM00)
| (0 << COM01)
| (0 << CS02)
| (1 << CS01)
| (0 << CS00);
OCR0 = 199;
/*
Timer 1 is free for your application!
*/
// Timer 2 - used for beeper:
TCCR2 = 0;
OCR2 = 0xFF;
// Enable timer interrupts:
TIMSK = (1 << OCIE0);
// SPI Master (SPI Mode 0, SCK Frequency is F_CPU/2, which means it is 8MHz
// on the RP6 CONTROL M32...):
SPCR = (0<<SPIE)
| (1<<SPE)
| (1<<MSTR)
| (0<<SPR0)
| (0<<SPR1)
| (0<<CPOL)
| (0<<CPHA);
SPSR = (1<<SPI2X);
sei(); // Enable Global Interrupts
}
/******************************************************************************
* Additional info
* ****************************************************************************
* Changelog:
* - v. 1.1 by Dominik S. Herwald
* - NEW: universal timer variable with 100祍 resolution added!
* - v. 1.0 (initial release) 16.05.2007 by Dominik S. Herwald
*
* ****************************************************************************
* Bugs, feedback, questions and modifications can be posted on the AREXX Forum
* on http://www.arexx.com/forum/ !
* Of course you can also write us an e-mail to: info@arexx.nl
* AREXX Engineering may publish updates from time to time on AREXX.com!
* ****************************************************************************
* - LICENSE -
* GNU GPL v2 (http://www.gnu.org/licenses/gpl.txt, a local copy can be found
* on the RP6 CD in the RP6 sorce code folders!)
* This program is free software. You can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* ****************************************************************************
*/
/*****************************************************************************/
// EOF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -