Files
tulflash/example.c

322 lines
6.8 KiB
C

//**********************************************************************
//**********************************************************************
//*** ***
//*** K O P Y T O V1.1 ***
//*** ***
//*** vandalized by Michal Procházka ***
//*** ***
//**********************************************************************
//**********************************************************************
#include <at89c51ed2.h>
#include <stdio.h>
#include <stdint.h>
#define TICK_RATE 100
#define NPER (0x10000 - (20000000 / 6 / TICK_RATE))
// I/O definitions
#define BUTTON_1 P3_2
#define BUTTON_2 P3_3
#define PIEZO P3_6
#define LED_RED P4_2
#define LED_YELLOW P4_3
#define LED_GREEN P4_4
#define POT P1_0
#define THERM P1_1
#define BULB P1_2
#define BAR_DAT P1_3
#define BAR_SCK P1_4
#define BAR_SCL P1_5
#define BAR_RCK P1_6
#define BAR_OE P1_7
#define LCD_RS_PIN P2_4
#define LCD_RW_PIN P2_5
#define LCD_EN_PIN P2_6
#define KEY_COL_1 P0_0
#define KEY_COL_2 P0_1
#define KEY_COL_3 P0_2
#define KEY_COL_4 P0_3
#define KEY_ROW_1 P0_4
#define KEY_ROW_2 P0_5
#define KEY_ROW_3 P0_6
#define KEY_ROW_4 P0_7
volatile uint16_t TIMER;
// Timer-based delay, waits for pause * 10 ms
void delay(int pause) {
TIMER = 1 + pause;
while(TIMER);
}
uint8_t lcd_pos;
#define LCD_RS 0x10 /* rgister select */
#define LCD_RW 0x20 /* read/write */
#define LCD_EN 0x40 /* chip enable */
// Quick'n'dirty CPU pause, just enough for the LCD to stabilize.
void lcd_pause(void) {
__asm__ ("nop");
}
// Reads the status register from the LCD.
uint8_t lcd_read_status(void) {
uint8_t temp;
lcd_pause();
P2 = LCD_RW | 0x0F;
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
temp = (P2 & 0x0F) << 4;
LCD_EN_PIN = 0;
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
temp = temp + (P2 & 0x0F);
LCD_EN_PIN = 0;
return temp;
}
// Writes a command to the LCD.
void lcd_send_cmd( uint8_t val )
{
lcd_pause();
P2 = (val >> 4) & 0x0F;
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
LCD_EN_PIN = 0;
lcd_pause();
P2 = (val & 0x0F);
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
LCD_EN_PIN = 0;
while(lcd_read_status() & 0x80);
}
// Writes a data value to the LCD.
void lcd_send_data(uint8_t val) {
lcd_pause();
P2 = LCD_RS | ((val >> 4) & 0x0F);
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
LCD_EN_PIN = 0;
lcd_pause();
P2 = LCD_RS | (val & 0x0F);
lcd_pause();
LCD_EN_PIN = 1;
lcd_pause();
LCD_EN_PIN = 0;
while(lcd_read_status() & 0x80);
}
// Clears the LCD.
void lcd_clear(void) {
lcd_send_cmd(0x01); /* display clear */
lcd_pos = 0;
}
// Initializes the LCD.
void lcd_init(void) {
P2 = 0; /* set RS, RW and EN low */
/* all delays are vital */
delay(50); /* power on delay - wait more than 15 ms */
for(uint8_t i = 0; i < 3; i++) {
P2 = 0x03; /* lce enable low */
delay(1); /* wait more than 100us */
P2 = LCD_EN | 0x03; /* lcd enable high */
delay(1); /* wait more than 100us */
P2 = 0x03; /* lce enable low */
delay(5); /* wait more than 4.1 ms */
}
P2 = 0x02; /* lcd enable low */
delay(1); /* wait more than 100us */
P2 = LCD_EN | 0x02; /* lcd enable high */
delay(1); /* wait more than 100us */
P2 = 0x02; /* lcd enable low */
delay(5); /* wait more than 100us */
lcd_send_cmd(0x28); /* 4 bit mode, 1/16 duty, 5x8 font */
lcd_send_cmd(0x08); /* display off */
lcd_clear();
lcd_send_cmd(0x06); /* entry mode */
lcd_send_cmd(0x0C); /* display on, blinking cursor off */
}
// Puts a character to the LCD. Correctly handles '\n'.
void lcd_putchar(char c) {
if(c == 10) {
if(lcd_pos < 40) lcd_pos = 40;
else lcd_pos = 0;
} else {
lcd_send_data(c);
lcd_pos++;
if(lcd_pos == 80) lcd_pos=0;
}
}
// Initializes the background tick timer (for delays).
void timer_init(void) {
CKCON0 = X2; // Enable 2x clock mode
// Initialize timer 0 as 16-bit countdown, timer 1 as 8-bit auto-reload countdown
TMOD = 0x21;
TCON = 0x50;
// Initialize timer 0 for 100 Hz
TL0 = (uint8_t)NPER;
TH0 = (uint8_t)(NPER >> 8);
// Enable interrupts only for timer 0
EA = 1;
ET0 = 1;
}
// Initializes the serial port (along with timer 2).
void serial_init(void) {
// Initialize timer 2 as 312500 Hz as the baud rate generator (for tulflash)
RCAP2H = 0xFF;
RCAP2L = 0xFC;
T2CON = 0x34;
// Initialize serial I/O
SCON = 0x50;
TI = 1;
}
// Writes a character to the serial port.
void serial_putchar(char c) {
while(TI == 0);
SBUF = c;
TI = 0;
}
__bit stdout_to_lcd = 0;
__bit stdout_to_serial = 0;
// Writes a character to standard output (LCD, serial or both).
int putchar(int c) {
if(stdout_to_lcd) {
lcd_putchar(c);
}
if(stdout_to_serial) {
serial_putchar(c);
}
return 0;
}
// Writes a 10-bit value to the LED bar. Bit 0 = bottom LED, bit 9 = top LED.
void led_bar_set(uint16_t n) {
uint8_t i;
BAR_RCK = 0;
BAR_SCL = 0;
BAR_SCL = 1;
BAR_SCK = 0;
for(i = 0; i < 10; i++) {
BAR_DAT = !(n & 1);
n >>= 1; // n = n >> 1
BAR_SCK = 1;
BAR_SCK = 0;
}
BAR_RCK = 1;
BAR_OE = 0;
}
// Reads a character from the keypad.
char keypad_read(void) {
P0 = 0xFF;
KEY_ROW_1 = 0;
lcd_pause();
if (!KEY_COL_1) return '1';
if (!KEY_COL_2) return '2';
if (!KEY_COL_3) return '3';
if (!KEY_COL_4) return 'A';
P0 = 0xFF;
KEY_ROW_2 = 0;
lcd_pause();
if (!KEY_COL_1) return '4';
if (!KEY_COL_2) return '5';
if (!KEY_COL_3) return '6';
if (!KEY_COL_4) return 'B';
P0 = 0xFF;
KEY_ROW_3 = 0;
lcd_pause();
if (!KEY_COL_1) return '7';
if (!KEY_COL_2) return '8';
if (!KEY_COL_3) return '9';
if (!KEY_COL_4) return 'C';
P0 = 0xFF;
KEY_ROW_4 = 0;
lcd_pause();
if (!KEY_COL_1) return '*';
if (!KEY_COL_2) return '0';
if (!KEY_COL_3) return '#';
if (!KEY_COL_4) return 'D';
return -1;
}
void main(void) {
timer_init();
lcd_init();
serial_init();
delay(1);
stdout_to_serial = 1;
stdout_to_lcd = 1;
int i = 1;
while(1) {
lcd_clear();
printf("hellOwOrld! %d\n", i);
led_bar_set(i);
LED_RED = !(i & 1);
LED_YELLOW = !(i & 2);
LED_GREEN = !(i & 4);
BULB = !(i & 8);
i++;
delay(TICK_RATE);
}
}
void timer0_handler(void) __interrupt(1) {
// Reload, 10ms
TL0 = (uint8_t)NPER;
TH0 = (uint8_t)(NPER >> 8);
if(TIMER != 0) TIMER--;
}