Exploring STC 8051 Microcontrollers – Coding
|
Software SPI and One Wire Bit-Banging
Software SPI is basically bit-banging ordinary GPIO pins to reproduce SPI signals. Software SPI is not needed unless hardware SPI peripheral is absent in the device or hardware SPI pins are used up for some other tasks. Though it is slow and require extra coding compared to hardware SPI, it is helpful for beginners to understand SPI-based hardware as it offers full control over all SPI signals.
Likewise, bit-banging can also be applied to communicate with one wire devices such as DHT11, DHT22, etc.
In this section, we will see how to use bit-banging to read a DHT11 sensor and show temperature and relative humidity data on a SPI-based SSD1306 OLED display.
Code
DHT11.h
#define DHT11_pin_init P10_quasi_bidirectional_mode
#define DHT11_pin_HIGH P10_high
#define DHT11_pin_LOW P10_low
#define DHT11_pin_IN P10_get_input
unsigned char values[5];
void DHT11_init(void);
unsigned char DHT11_get_byte(void);
unsigned char DHT11_get_data(void);
DHT11.c
#include "DHT11.h"
extern unsigned char values[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
void DHT11_init(void)
{
DHT11_pin_init;
delay_ms(1000);
}
unsigned char DHT11_get_byte(void)
{
unsigned char s = 0x08;
unsigned char value = 0x00;
while(s > 0)
{
value <<= 1;
while(DHT11_pin_IN == LOW);
large_delay_TMR_0(30);
if(DHT11_pin_IN == HIGH)
{
value |= 1;
}
while(DHT11_pin_IN == HIGH);
s--;
}
return value;
}
unsigned char DHT11_get_data(void)
{
unsigned char s = 0;
unsigned char check_sum = 0;
DHT11_pin_HIGH;
DHT11_pin_LOW;
large_delay_TMR_0(18000);
DHT11_pin_HIGH;
large_delay_TMR_0(26);
if(DHT11_pin_IN == HIGH)
{
return 1;
}
large_delay_TMR_0(80);
if(DHT11_pin_IN == LOW)
{
return 2;
}
large_delay_TMR_0(80);
for(s = 0; s <= 4; s++)
{
values[s] = DHT11_get_byte();
}
DHT11_pin_HIGH;
for(s = 0; s < 4; s++)
{
check_sum += values[s];
}
if(check_sum != values[4])
{
return 3;
}
else
{
return 0;
}
}
font.c
const unsigned char font_regular[92][6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [ 91
0x00, 0x02, 0x04, 0x08, 0x10, 0x20, // \92
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14 // horiz lines
};
SSD1306.h
#define SSD1306_CS_PIN_HIGH P03_high
#define SSD1306_CS_PIN_LOW P03_low
#define SSD1306_DC_PIN_HIGH P04_high
#define SSD1306_DC_PIN_LOW P04_low
#define SSD1306_RST_PIN_HIGH P05_high
#define SSD1306_RST_PIN_LOW P05_low
#define SSD1306_SDA_PIN_HIGH P06_high
#define SSD1306_SDA_PIN_LOW P06_low
#define SSD1306_SCK_PIN_HIGH P07_high
#define SSD1306_SCK_PIN_LOW P07_low
#define DAT 1
#define CMD 0
#define Set_Lower_Column_Start_Address_CMD 0x00
#define Set_Higher_Column_Start_Address_CMD 0x10
#define Set_Memory_Addressing_Mode_CMD 0x20
#define Set_Column_Address_CMD 0x21
#define Set_Page_Address_CMD 0x22
#define Set_Display_Start_Line_CMD 0x40
#define Set_Contrast_Control_CMD 0x81
#define Set_Charge_Pump_CMD 0x8D
#define Set_Segment_Remap_CMD 0xA0
#define Set_Entire_Display_ON_CMD 0xA4
#define Set_Normal_or_Inverse_Display_CMD 0xA6
#define Set_Multiplex_Ratio_CMD 0xA8
#define Set_Display_ON_or_OFF_CMD 0xAE
#define Set_Page_Start_Address_CMD 0xB0
#define Set_COM_Output_Scan_Direction_CMD 0xC0
#define Set_Display_Offset_CMD 0xD3
#define Set_Display_Clock_CMD 0xD5
#define Set_Pre_charge_Period_CMD 0xD9
#define Set_Common_HW_Config_CMD 0xDA
#define Set_VCOMH_Level_CMD 0xDB
#define Set_NOP_CMD 0xE3
#define Horizontal_Addressing_Mode 0x00
#define Vertical_Addressing_Mode 0x01
#define Page_Addressing_Mode 0x02
#define Disable_Charge_Pump 0x00
#define Enable_Charge_Pump 0x04
#define Column_Address_0_Mapped_to_SEG0 0x00
#define Column_Address_0_Mapped_to_SEG127 0x01
#define Normal_Display 0x00
#define Entire_Display_ON 0x01
#define Non_Inverted_Display 0x00
#define Inverted_Display 0x01
#define Display_OFF 0x00
#define Display_ON 0x01
#define Scan_from_COM0_to_63 0x00
#define Scan_from_COM63_to_0 0x08
#define x_size 128
#define x_max x_size
#define x_min 0
#define y_size 64
#define y_max 8
#define y_min 0
#define ON 1
#define OFF 0
#define ROUND 1
#define SQUARE 0
#define buffer_size 1024//(x_max * y_max)
unsigned char buffer[buffer_size];
void OLED_init(void);
void OLED_reset_sequence(void);
void OLED_write(unsigned char value, unsigned char type);
void OLED_gotoxy(unsigned char x_pos, unsigned char y_pos);
void OLED_fill(unsigned char bmp_data);
void OLED_clear_screen(void);
void OLED_clear_buffer(void);
void OLED_cursor(unsigned char x_pos, unsigned char y_pos);
void OLED_draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char bmp_img[]);
void OLED_print_char(unsigned char x_pos, unsigned char y_pos, unsigned char ch);
void OLED_print_string(unsigned char x_pos, unsigned char y_pos, unsigned char *ch);
void OLED_print_chr(unsigned char x_pos, unsigned char y_pos, signed long value);
void OLED_print_int(unsigned char x_pos, unsigned char y_pos, signed long value);
void OLED_print_decimal(unsigned char x_pos, unsigned char y_pos, unsigned long value, unsigned char points);
void OLED_print_float(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points);
void Draw_Pixel(unsigned char x_pos, unsigned char y_pos, short colour);
void Draw_Line(signed long x1, signed long y1, signed long x2, signed long y2, short colour);
void Draw_Rectangle(signed long x1, signed long y1, signed long x2, signed long y2, short fill, short colour, short type);
void Draw_Circle(signed long xc, signed long yc, signed long radius, short fill, short colour);
SSD1306.c
#include "SSD1306.h"
#include "fonts.c"
void OLED_init(void)
{
P03_push_pull_mode;
P04_push_pull_mode;
P05_push_pull_mode;
P06_push_pull_mode;
P07_push_pull_mode;
OLED_clear_buffer();
OLED_reset_sequence();
OLED_write((Set_Display_ON_or_OFF_CMD + Display_OFF) , CMD);;
OLED_write(Set_Display_Clock_CMD, CMD);
OLED_write(0x80, CMD);
OLED_write(Set_Multiplex_Ratio_CMD, CMD);
OLED_write(0x3F, CMD);
OLED_write(Set_Display_Offset_CMD, CMD);
OLED_write(0x00, CMD);
OLED_write((Set_Display_Start_Line_CMD | 0x00), CMD);
OLED_write(Set_Charge_Pump_CMD, CMD);
OLED_write((Set_Higher_Column_Start_Address_CMD | 0x04), CMD);
OLED_write(Set_Memory_Addressing_Mode_CMD, CMD);
OLED_write(Page_Addressing_Mode, CMD);
OLED_write((Set_Segment_Remap_CMD | Column_Address_0_Mapped_to_SEG127), CMD);
OLED_write((Set_COM_Output_Scan_Direction_CMD | Scan_from_COM63_to_0), CMD);
OLED_write(Set_Common_HW_Config_CMD, CMD);
OLED_write(0x12, CMD);
OLED_write(Set_Contrast_Control_CMD, CMD);
OLED_write(0xCF, CMD);
OLED_write(Set_Pre_charge_Period_CMD, CMD);
OLED_write(0xF1, CMD);
OLED_write(Set_VCOMH_Level_CMD, CMD);
OLED_write(0x40, CMD);
OLED_write((Set_Entire_Display_ON_CMD | Normal_Display), CMD);
OLED_write((Set_Normal_or_Inverse_Display_CMD | Non_Inverted_Display), CMD);
OLED_write((Set_Display_ON_or_OFF_CMD + Display_ON) , CMD);
OLED_gotoxy(0, 0);
OLED_clear_screen();
}
void OLED_reset_sequence(void)
{
SSD1306_SCK_PIN_HIGH;
SSD1306_RST_PIN_LOW;
delay_ms(60);
SSD1306_RST_PIN_HIGH;
SSD1306_SCK_PIN_LOW;
delay_ms(60);
}
void OLED_write(unsigned char value, unsigned char type)
{
unsigned char s = 0x08;
SSD1306_CS_PIN_LOW;
switch(type)
{
case DAT:
{
SSD1306_DC_PIN_HIGH;
break;
}
default:
{
SSD1306_DC_PIN_LOW;
break;
}
}
while(s > 0)
{
if((value & 0x80) != 0x00)
{
SSD1306_SDA_PIN_HIGH;
}
else
{
SSD1306_SDA_PIN_LOW;
}
SSD1306_SCK_PIN_HIGH;
SSD1306_SCK_PIN_LOW;
value <<= 1;
s--;
};
SSD1306_CS_PIN_HIGH;
}
void OLED_gotoxy(unsigned char x_pos, unsigned char y_pos)
{
OLED_write((Set_Page_Start_Address_CMD + y_pos), CMD);
OLED_write(((x_pos & 0x0F) | Set_Lower_Column_Start_Address_CMD), CMD);
OLED_write((((x_pos & 0xF0) >> 0x04) | Set_Higher_Column_Start_Address_CMD), CMD);
}
void OLED_fill(unsigned char bmp_data)
{
unsigned char x_pos = 0x00;
unsigned char page = 0x00;
for(page = y_min; page < y_max; page++)
{
OLED_write((Set_Page_Start_Address_CMD + page), CMD);
OLED_write(Set_Lower_Column_Start_Address_CMD, CMD);
OLED_write(Set_Higher_Column_Start_Address_CMD, CMD);
for(x_pos = x_min; x_pos < x_max; x_pos++)
{
OLED_write(bmp_data, DAT);
}
}
}
void OLED_clear_screen(void)
{
OLED_fill(0x00);
}
void OLED_clear_buffer(void)
{
unsigned long s = 0x00;
for(s = 0; s < buffer_size; s++)
{
buffer[s] = 0x00;
}
}
void OLED_cursor(unsigned char x_pos, unsigned char y_pos)
{
unsigned char i = 0x00;
if(y_pos != 0x00)
{
if(x_pos == 1)
{
OLED_gotoxy(0x00, (y_pos + 0x02));
}
else
{
OLED_gotoxy((0x50 + ((x_pos - 0x02) * 0x06)), (y_pos + 0x02));
}
for(i = 0; i < 6; i++)
{
OLED_write(0xFF, DAT);
}
}
}
void OLED_draw_bitmap(unsigned char xb, unsigned char yb, unsigned char xe, unsigned char ye, unsigned char bmp_img[])
{
unsigned long s = 0x0000;
unsigned char x_pos = 0x00;
unsigned char y_pos = 0x00;
for(y_pos = yb; y_pos <= ye; y_pos++)
{
OLED_gotoxy(xb, y_pos);
for(x_pos = xb; x_pos < xe; x_pos++)
{
OLED_write(bmp_img[s++], DAT);
}
}
}
void OLED_print_char(unsigned char x_pos, unsigned char y_pos, unsigned char ch)
{
unsigned char chr = 0x00;
unsigned char s = 0x00;
chr = (ch - 32);
if(x_pos > (x_max - 6))
{
x_pos = 0;
y_pos++;
}
OLED_gotoxy(x_pos, y_pos);
for(s = 0x00; s < 0x06; s++)
{
OLED_write(font_regular[chr][s], DAT);
}
}
void OLED_print_string(unsigned char x_pos, unsigned char y_pos, unsigned char *ch)
{
unsigned char chr = 0x00;
unsigned char i = 0x00;
unsigned char j = 0x00;
while(ch[j] != '\0')
{
chr = (ch[j] - 32);
if(x_pos > (x_max - 0x06))
{
x_pos = 0x00;
y_pos++;
}
OLED_gotoxy(x_pos, y_pos);
for(i = 0x00; i < 0x06; i++)
{
OLED_write(font_regular[chr][i], DAT);
}
j++;
x_pos += 6;
}
}
void OLED_print_chr(unsigned char x_pos, unsigned char y_pos, signed long value)
{
unsigned char ch = 0x00;
if(value < 0x00)
{
OLED_print_char(x_pos, y_pos, '-');
value = -value;
}
else
{
OLED_print_char(x_pos, y_pos,' ');
}
if((value > 99) && (value <= 999))
{
ch = (value / 100);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 18), y_pos , (48 + ch));
}
else if((value > 9) && (value <= 99))
{
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
OLED_print_char((x_pos + 18), y_pos , 32);
}
else if((value >= 0) && (value <= 9))
{
ch = (value % 10);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
OLED_print_char((x_pos + 12), y_pos , 32);
OLED_print_char((x_pos + 18), y_pos , 32);
}
}
void OLED_print_int(unsigned char x_pos, unsigned char y_pos, signed long value)
{
unsigned char ch = 0x00;
if(value < 0)
{
OLED_print_char(x_pos, y_pos, '-');
value = -value;
}
else
{
OLED_print_char(x_pos, y_pos,' ');
}
if(value > 9999)
{
ch = (value / 10000);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = ((value % 10000)/ 1000);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
ch = ((value % 1000) / 100);
OLED_print_char((x_pos + 18), y_pos , (48 + ch));
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 24), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 30), y_pos , (48 + ch));
}
else if((value > 999) && (value <= 9999))
{
ch = ((value % 10000)/ 1000);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = ((value % 1000) / 100);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 18), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 24), y_pos , (48 + ch));
OLED_print_char((x_pos + 30), y_pos , 32);
}
else if((value > 99) && (value <= 999))
{
ch = ((value % 1000) / 100);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 18), y_pos , (48 + ch));
OLED_print_char((x_pos + 24), y_pos , 32);
OLED_print_char((x_pos + 30), y_pos , 32);
}
else if((value > 9) && (value <= 99))
{
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
ch = (value % 10);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
OLED_print_char((x_pos + 18), y_pos , 32);
OLED_print_char((x_pos + 24), y_pos , 32);
OLED_print_char((x_pos + 30), y_pos , 32);
}
else
{
ch = (value % 10);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
OLED_print_char((x_pos + 12), y_pos , 32);
OLED_print_char((x_pos + 18), y_pos , 32);
OLED_print_char((x_pos + 24), y_pos , 32);
OLED_print_char((x_pos + 30), y_pos , 32);
}
}
void OLED_print_decimal(unsigned char x_pos, unsigned char y_pos, unsigned long value, unsigned char points)
{
unsigned char ch = 0x00;
OLED_print_char(x_pos, y_pos, '.');
ch = (value / 1000);
OLED_print_char((x_pos + 6), y_pos , (48 + ch));
if(points > 1)
{
ch = ((value % 1000) / 100);
OLED_print_char((x_pos + 12), y_pos , (48 + ch));
if(points > 2)
{
ch = ((value % 100) / 10);
OLED_print_char((x_pos + 18), y_pos , (48 + ch));
if(points > 3)
{
ch = (value % 10);
OLED_print_char((x_pos + 24), y_pos , (48 + ch));
}
}
}
}
void OLED_print_float(unsigned char x_pos, unsigned char y_pos, float value, unsigned char points)
{
signed long tmp = 0x0000;
tmp = value;
OLED_print_int(x_pos, y_pos, tmp);
tmp = ((value - tmp) * 10000);
if(tmp < 0)
{
tmp = -tmp;
}
if((value >= 9999) && (value < 99999))
{
OLED_print_decimal((x_pos + 36), y_pos, tmp, points);
}
else if((value >= 999) && (value < 9999))
{
OLED_print_decimal((x_pos + 30), y_pos, tmp, points);
}
else if((value >= 99) && (value < 999))
{
OLED_print_decimal((x_pos + 24), y_pos, tmp, points);
}
else if((value >= 9) && (value < 99))
{
OLED_print_decimal((x_pos + 18), y_pos, tmp, points);
}
else if(value < 9)
{
OLED_print_decimal((x_pos + 12), y_pos, tmp, points);
if((value) < 0)
{
OLED_print_char(x_pos, y_pos, '-');
}
else
{
OLED_print_char(x_pos, y_pos, ' ');
}
}
}
void Draw_Pixel(unsigned char x_pos, unsigned char y_pos, short colour)
{
unsigned char value = 0x00;
unsigned char page = 0x00;
unsigned char bit_pos = 0x00;
page = (y_pos / y_max);
bit_pos = (y_pos - (page * y_max));
value = buffer[((page * x_max) + x_pos)];
if((colour & 0x01) != 0)
{
value |= (1 << bit_pos);
}
else
{
value &= (~(1 << bit_pos));
}
buffer[((page * x_max) + x_pos)] = value;
OLED_gotoxy(x_pos, page);
OLED_write(value, DAT);
}
void Draw_Line(signed long x1, signed long y1, signed long x2, signed long y2, short colour)
{
signed long dx = 0x0000;
signed long dy = 0x0000;
signed long stepx = 0x0000;
signed long stepy = 0x0000;
signed long fraction = 0x0000;
dy = (y2 - y1);
dx = (x2 - x1);
if (dy < 0)
{
dy = -dy;
stepy--;
}
else
{
stepy = 1;
}
if (dx < 0)
{
dx = -dx;
stepx--;
}
else
{
stepx = 1;
}
dx <<= 1;
dy <<= 1;
Draw_Pixel(((unsigned char)x1), ((unsigned char)y1), colour);
if(dx > dy)
{
fraction = (dy - (dx >> 1));
while (x1 != x2)
{
if(fraction >= 0)
{
y1 += stepy;
fraction -= dx;
}
x1 += stepx;
fraction += dy;
Draw_Pixel(((unsigned char)x1), ((unsigned char)y1), colour);
}
}
else
{
fraction = (dx - (dy >> 1));
while (y1 != y2)
{
if (fraction >= 0)
{
x1 += stepx;
fraction -= dy;
}
y1 += stepy;
fraction += dx;
Draw_Pixel(((unsigned char)x1), ((unsigned char)y1), colour);
}
}
}
void Draw_Rectangle(signed long x1, signed long y1, signed long x2, signed long y2, short fill, short colour, short type)
{
unsigned char i = 0x00;
unsigned char xmin = 0x00;
unsigned char xmax = 0x00;
unsigned char ymin = 0x00;
unsigned char ymax = 0x00;
if(fill == ON)
{
if(x1 < x2)
{
xmin = x1;
xmax = x2;
}
else
{
xmin = x2;
xmax = x1;
}
if(y1 < y2)
{
ymin = y1;
ymax = y2;
}
else
{
ymin = y2;
ymax = y1;
}
for(i = ymin; i <= ymax; ++i)
{
Draw_Line(xmin, i, xmax, i, colour);
}
}
else
{
Draw_Line(x1, y1, x2, y1, colour);
Draw_Line(x1, y2, x2, y2, colour);
Draw_Line(x1, y1, x1, y2, colour);
Draw_Line(x2, y1, x2, y2, colour);
}
if(type != SQUARE)
{
Draw_Pixel(((unsigned char)x1), ((unsigned char)y1), ~colour);
Draw_Pixel(((unsigned char)x1), ((unsigned char)y2), ~colour);
Draw_Pixel(((unsigned char)x2), ((unsigned char)y1), ~colour);
Draw_Pixel(((unsigned char)x2), ((unsigned char)y2), ~colour);
}
}
void Draw_Circle(signed long xc, signed long yc, signed long radius, short fill, short colour)
{
signed long a = 0x0000;
signed long b = 0x0000;
signed long P = 0x0000;
b = radius;
P = (1 - b);
do
{
if(fill == ON)
{
Draw_Line((xc - a), (yc + b), (xc + a), (yc + b), colour);
Draw_Line((xc - a), (yc - b), (xc + a), (yc - b), colour);
Draw_Line((xc - b), (yc + a), (xc + b), (yc + a), colour);
Draw_Line((xc - b), (yc - a), (xc + b), (yc - a), colour);
}
else
{
Draw_Pixel((xc + a), (yc + b), colour);
Draw_Pixel((xc + b), (yc + a), colour);
Draw_Pixel((xc - a), (yc + b), colour);
Draw_Pixel((xc - b), (yc + a), colour);
Draw_Pixel((xc + b), (yc - a), colour);
Draw_Pixel((xc + a), (yc - b), colour);
Draw_Pixel((xc - a), (yc - b), colour);
Draw_Pixel((xc - b), (yc - a), colour);
}
if(P < 0)
{
P += (3 + (2 * a++));
}
else
{
P += (5 + (2 * ((a++) - (b--))));
}
}while(a <= b);
}
main.c
#include "STC8xxx.h"
#include "BSP.h"
#include "DHT11.c"
#include "SSD1306.c"
void setup(void);
void main(void)
{
unsigned char state = 0x00;
setup();
OLED_print_string(24, 0, "Temp/Deg C");
OLED_print_string(24, 4, "Rel.Hum /%");
while(1)
{
state = DHT11_get_data();
switch(state)
{
case 1:
{
}
case 2:
{
OLED_print_string(56, 2, " ");
OLED_print_string(56, 6, " ");
break;
}
case 3:
{
OLED_print_string(56, 2, "--");
OLED_print_string(56, 6, "--");
break;
}
default:
{
OLED_print_chr(55, 2, values[2]);
OLED_print_chr(55, 6, values[0]);
break;
}
}
delay_ms(1000);
};
}
void setup(void)
{
CLK_set_sys_clk(IRC_24M, 2, MCLK_SYSCLK_no_output, MCLK_out_P54);
DHT11_init();
OLED_init();
}
Schematic
Explanation
DHT11’s logical one and zero timing diagrams below show that it too uses time-slotting mechanism just like DS18B20. However, its way of communication or protocol is not same as that of DS18B20’s and codes are not compatible amongst each other.
From the above timing diagrams, it is clear that the difference between these two signals is the high time. Thus, after sensing low input we should wait for about 30µs before trying to determine if the sensor sent a zero time-slot or a one time-slot. This is so because if it sent a logical zero then after 30µs of delay, there should be no floating or logic high signal in DHT11’s communication pin. If it is otherwise then a logical one time slot should be expected. This is what the following code does.
unsigned char DHT11_get_byte(void)
{
unsigned char s = 0x08;
unsigned char value = 0x00;
while(s > 0)
{
value <<= 1;
while(DHT11_pin_IN == LOW);
large_delay_TMR_0(30);
if(DHT11_pin_IN == HIGH)
{
value |= 1;
}
while(DHT11_pin_IN == HIGH);
s--;
}
return value;
}
At this point, it is necessary to mention that instead of traditional software-based delay library that relies on wasting CPU cycles, hardware-based delay library has been used in this code. This library (tmr_delay.h) generates more accurate time delays.
Now let’s see how SSD1306 OLED display can be bit-banged. First, notice its timing diagram.
The timing diagram suggests:
- SPI clock (SCLK) is held low in idle mode.
- SPI data (SDIN) is shifted or clocked during the rising edge or low-to-high transition of SPI clock.
- SPI chip/slave select (CS) should be held low during data transfer only and for the rest of the times, it should be held high.
All these points suggest us that it is a Mode 0 SPI communication and we can craft a code using these data as shown below. It is a mere timing diagram to code translation.
void OLED_write(unsigned char value, unsigned char type)
{
unsigned char s = 0x08;
SSD1306_CS_PIN_LOW;
switch(type)
{
case DAT:
{
SSD1306_DC_PIN_HIGH;
break;
}
default:
{
SSD1306_DC_PIN_LOW;
break;
}
}
while(s > 0)
{
if((value & 0x80) != 0x00)
{
SSD1306_SDA_PIN_HIGH;
}
else
{
SSD1306_SDA_PIN_LOW;
}
SSD1306_SCK_PIN_HIGH;
SSD1306_SCK_PIN_LOW;
value <<= 1;
s--;
};
SSD1306_CS_PIN_HIGH;
}
Demo
|
hello.
this is a very good effort to document all and still share with us. thank you very much.
I have one doubt . which programming tool are you using ?
Hi, I am trying to understand the STC15w408as chip, and found this site after weeks of searching for something that sets the output of the GPIO pins to a different state. I have a the 28 pin stc15w and have connected it up with a FTDI board and can write to it using PlatformIO. The thing is, the GPIO ports if just switched on or do a reset they are in the HIGH state and I am trying to make them LOW when you do a reset.
Is your BSP code doing this and for what port or GPIO pin is it setting? I could change your P52 and P55 in your SETUP to the GPIO pins on my development board but not under standing the BSP Code.
Wonder if you get this post? but any help would be gratefully received.
Hi,
How Purchase the development board. Please,give the purchase link for this Development board.
https://www.alibaba.com/product-detail/Development-board-1T-STC8A8K64S4A12-single-chip_62391507065.html
https://world.taobao.com/item/600882463994.htm
https://www.amazon.ca/STC8A8K64S4A12-Development-Controller-Module-Minimal/dp/B08D3Y3R6T
How To read and write string data using IAP into memory
void IAP_erase(unsigned int address)
{
IAP_CONTR = 0x80; //?? IAP
IAP_TPS = 12;
// IAP_CONTR = IAP_WT;
IAP_CMD = IAP_erase_command;
IAP_address(address);
IAP_trigger;
_nop_();
_nop_();
_nop_();
IAP_clear;
}
void IAP_send_string(unsigned int uc_send_addr,unsigned char *uca_send_string,unsigned int uc_number_of_bytes)
{
unsigned int buff_cntr=0;
do
{
IAP_CONTR = 0x80; //?? ISP/IAP ??
IAP_TPS = (unsigned char)(11509200 / 1000000L); //??????
IAP_CMD = IAP_write_command;
// IAP_CMD = IAP_write_command;
IAP_ADDRH = uc_send_addr / 256; //??????(??????????????)
IAP_ADDRL = uc_send_addr % 256; //??????
IAP_DATA = uca_send_string[buff_cntr]; //???? ISP_DATA,????????????
IAP_trigger;//IAP_TRIG();
_nop_();
_nop_();
_nop_();
uc_send_addr++;
// uca_send_string++;
buff_cntr++;
IAP_clear;
delay_ms(8);
}while(–uc_number_of_bytes);
}
void IAP_read_string(unsigned int uc_read_addr,unsigned char *data_read,unsigned int uc_number_of_bytes)
{
unsigned int buff_cntr=0;
do{
IAP_CONTR = 0x80; //?? ISP/IAP ??
IAP_TPS = (unsigned char)(11059200 / 1000000L); //??????
IAP_CMD = IAP_read_command;
// IAP_CMD = IAP_read_command;
IAP_ADDRH = uc_read_addr / 256; //??????(??????????????)
IAP_ADDRL = uc_read_addr % 256; //??????
IAP_trigger;//IAP_TRIG(); //?? 5AH,?? A5H ? ISP/IAP ?????,
//???????
//?? A5H ?, ISP/IAP ?????????
//CPU ?? IAP ???,?????????
_nop_();
_nop_();
_nop_();
data_read[buff_cntr] = IAP_DATA; //???????
uc_read_addr++;
// data_read++;
buff_cntr++;
IAP_clear;
delay_ms(8);
}while(–uc_number_of_bytes);
}
stores only last byte to all bytes of flash memory sector… memory sector selected is 0xF600
Hi, I am using STC MCU since 10 years. Tech support is ZERO. but they are low cost, very stable. Now I have a problem when the chip that I used is obsolete. Now start to use STC8C2K64S4-28I-LQFP32 but no stc8Cxx.h file, I am using stc8Hxx.h file which compiles but in some stage freeze, the existing firmware. With stc8hxx.h file I can compile STC8F2K64S4-28I-LQFP32 and works not bad
.
I wrote them many times for the stc8Cxx.h file never got answer. Where Can I find that file?
Thank you
Give me detail 8f2k64s281MCU read and write programmer
Give me detail 8f2k64s281reed and write programmer distal
Hi. Can you explain how to use I2C in the slave mode ?
I tried STC8G1K08A i2c in slave mode. Doesn’t work (no response). It does not enter interrupt, even on a start condition (everything according to the code in the documentation). I also tried master mode – it works.
Thanks for these tutorials. I’m getting back into STCmicro coding now, having left them alone for the past several years. Back then I only used the STC89C52RC (and C54RD) but this time I’m also using the more powerful STC15 and STC8 types. Your blogs provide a wealth of useful information.
Hello,
You have done great job with all these tutorials. I am an electronics engineer trying to learn some new stuff. I am located in Greece , Europe and I would like to purchase the development board that you are using and download some datasheets in English if possible but I cannot find them anywhere. Could you please help me?
I suggest you buy from AliExpress or similar platform that is available in your country…. You can find the English datasheet here. English documentation can be found in STC’s official websites such as this one….
Thank you very much for your help!!!
i always get excited when you release new tutorials ,you are really doing a great job i wish i could write code and develop libraries like you.
Well, this is very nice and thorough tutorial indeed, many thanks!
Unfortunately I doubt there is good any reason to learn the STC platform beyond curiosity.
The STC 8051, although pretty evolved from the original 8051 ISA, does not offer anything crucial to justify the relatively high price of these micros and development tools along with certain cumbersomeness of this ancient platform.
They simply can not compete even with the legacy Cortex M0 in any way. I am even not aware about any affordable debugger/emulator for them.
All in all, I would never recommend anybody to start learning/using any 8051 without some very good reason to do so.