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

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

Related Posts

17 comments

  • 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.

  • 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

  • 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 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.

Leave a Reply

Your email address will not be published. Required fields are marked *