[Self-study 51 MCU] 10 -- PWM introduction, 51 MCU RAM area division

Publisher:cw57324588Latest update time:2021-10-20 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. PWM Introduction

PWM (Pulse Width Modulation), also known as pulse width modulation in Chinese, can use digital signals to achieve the effect of an analog signal. Pulse width modulation is to change the pulse width to achieve different effects. See Figure 10-1 for three groups of pulse signals.

It is a waveform with a period of 10ms and a frequency of 100Hz. The width of each group of high and low level pulses is different, that is, the duty cycle (the proportion of the high level time in the entire period) is different.


In digital circuits, there are only two states, 0 and 1. In the small light, 0 is off and 1 is on. When the small light is turned on and off at intervals, and the interval time is continuously reduced, and the frequency is greater than 100Hz, it appears to the naked eye that it remains on all the time. The time when the small light is on and off is continuously changed in each cycle, and the brightness of the small light will also change. This achieves the effect of an analog circuit. It is no longer pure 0 and 1, and the brightness is constantly changing.


2. RAM area division of 51 MCU

The RAM area of ​​51 MCU is divided into two parts: on-chip RAM and off-chip RAM. The addresses of on-chip RAM and off-chip RAM are not connected. Now almost all 51 MCU chips have off-chip RAM integrated inside. Below are the keywords and addresses of different RAMs in C51.


data: On-chip RAM from 0x00 to 0x7F.

idata: On-chip RAM from 0x00 to 0xFF.

pdata: external RAM from 0x00 to 0xFF.

xdata: off-chip RAM from 0x0000 to 0xFFFF.

-Description: STC89C52RC has a total of 512 bytes of RAM, divided into 256 bytes of on-chip RAM and 256 bytes of off-chip RAM. data is part of idata, and pdata is part of xdata.


Internal RAM, the default variables are defined in the data area. The data area RAM is accessed directly and has the fastest execution speed. idata is indirect addressing and is slower than data. It is usually not desirable to access 0x80–0xFF, because this area is usually used for interrupt and function call stacks, so the idata area is usually not used.

External RAM, pdata and xdata are all accessed through indirect addressing. The access speed of xdata is the slowest, but the access range of xdata is the widest.


3. Improvement of digital tube scanning function algorithm

Original code

P0 = 0xFF; //display blanking

switch(i)

{

case 0: ADDR2 = 0; ADDR1 = 0; ADDR0 = 0; i++; P0 = Ledbuff[0];break;

case 1: ADDR2 = 0; ADDR1 = 0; ADDR0 = 1; i++; P0 = Ledbuff[1];break;

case 2: ADDR2 = 0; ADDR1 = 1; ADDR0 = 0; i++; P0 = Ledbuff[2];break;

case 3: ADDR2 = 0; ADDR1 = 1; ADDR0 = 1; i++; P0 = Ledbuff[3];break;

case 4: ADDR2 = 1; ADDR1 = 0; ADDR0 = 0; i++; P0 = Ledbuff[4];break;

case 5: ADDR2 = 1; ADDR1 = 0; ADDR0 = 1; i=0; P0 = Ledbuff[5];break;

default:break;

}


Improved code

P0 = 0xFF; // Turn off all segment selection bits and display blanking

P1 = (P1 & 0xF8) | i; //Assign the bit selection index value to the lower three bits of port P1

P0 = Ledbuf[i]; //The data at the index position in the buffer is sent to port P0

i++; //Index increment loop, traversing the entire buffer

if(i > 5)

{

i = 0;

}


4. Long and short key application-simulating time bomb applet

//Long and short key application

#include


sbit ADDR3 = P1^3;

sbit ENLED = P1^4;

sbit BUZZ = P1^6;

sbit KEY_IN_1 = P2^4;

sbit KEY_IN_2 = P2^5;

sbit KEY_IN_3 = P2^6;

sbit KEY_IN_4 = P2^7;

sbit KEY_OUT_1 = P2^3;

sbit KEY_OUT_2 = P2^2;

sbit KEY_OUT_3 = P2^1;

sbit KEY_OUT_4 = P2^0;


unsigned char code LedChar[] = { // Digital tube display character conversion table

0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,

0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E

};


unsigned char LedBuff[]={ //Digital tube + independent LED display buffer

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

};


unsigned char KeySta[4][4] = { //Current status of all matrix keys

{1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}

};


unsigned char code KeyCodeMap[4][4] = { //mapping table from matrix key numbers to standard keyboard key codes

    { 0x31, 0x32, 0x33, 0x26 }, //Number key 1, number key 2, number key 3, up key

    { 0x34, 0x35, 0x36, 0x25 }, //Number key 4, number key 5, number key 6, left key

    { 0x37, 0x38, 0x39, 0x28 }, //Number key 7, number key 8, number key 9, down key

    { 0x30, 0x1B, 0x0D, 0x27 } //Number key 0, ESC key, Enter key, Right key

};


unsigned long pdata KeyDownTime[4][4] = { //The duration of each key being pressed, in ms

{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}

};


bit flag1s = 0; //1s timing flag

bit flagStart = 0; // countdown start flag

bit enBuzz = 0; //Buzzer is enabled

unsigned long CountDown = 0; // countdown counter

unsigned char T0RH; //high byte of T0 reload value

unsigned char T0RL; // low byte of T0 reload value



void ConfigTimer0(unsigned char ms);

void Shownumber(unsigned long num);

void KeyDriver();

void KeyAction(unsigned char keycode);

void Keyscan();

void Ledscan();


void main()

{

EA = 1; // Enable general interrupt

ENLED = 0; //Select digital tube and independent LED

ADDR3 = 1;

ConfigTimer0(1); //Configure T0 timing 1ms

Shownumber(0); //Power-on display


while(1)

{

KeyDriver(); //Call key driver function

if(flag1s && flagStart) //When the countdown starts and the 1 second timer arrives, process the countdown

{

flag1s = 0;

if(CountDown > 0) //When the countdown does not reach 0, the counter decreases

{

CountDown--;

Shownumber(CountDown); //Refresh countdown display

if(CountDown == 0) //When it decreases to 0, sound and light alarm will be executed

{

enBuzz = 1; //Start the buzzer

LedBuff[6] = 0x00; //Light up the independent LED

}

}

}

}

}


//Configure and start T0, ms-T0 timing time

void ConfigTimer0(unsigned char ms)

{

unsigned long tmp; //temporary variable

tmp = 11059200 / 12; //Timer counting frequency

tmp = (tmp * ms) / 1000; //Calculate the required count value

tmp = 65536 - tmp + 28; //Calculate the timer reload value and compensate for the error caused by interrupt delay

T0RH = (unsigned char)(tmp >> 8); //Timer reload value is split into high and low bytes

T0RL = (unsigned char)tmp;

TMOD &= 0xF0; // Clear the control bit of T0

TMOD |= 0x01; //Configure T0 to mode 1

TH0 = T0RH; //Load T0 reload value

TL0 = T0RL;

ET0 = 1; // Enable T0 interrupt

TR0 = 1; //Start T0


}


//Display an unsigned long integer on the digital tube, num is the number to be displayed

void Shownumber(unsigned long num)

{

signed char i;

unsigned char buf[6];

for(i = 0; i < 6; i++) //Convert the long integer to a 6-digit decimal array

{

buf[i] = num % 10;

num /= 10;

}

for(i = 5; i >= 1; i--) //Starting from the highest position, if 0 is encountered, it will be converted to a space, and if it is not 0, it will exit the loop

{

if(buf[i] == 0)

{

LedBuff[i] = 0xFF;

}

else

{

break;

}

}

for(; i>= 0; i--) //The remaining low bits are converted to display characters of the digital tube

{

LedBuff[i] = LedChar[buf[i]];

}

}


//Key driving function, detects key actions, and calls corresponding action functions. It needs to be called in the main loop

void KeyDriver()

{

unsigned char i, j;

static unsigned char pdata backup[4][4] = { //Backup the key value and save the previous value

{1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}

};

    static unsigned long pdata Timethr[4][4] = { //Time threshold for fast input execution

  {1000,1000,1000,1000},{1000,1000,1000,1000},

  {1000,1000,1000,1000},{1000,1000,1000,1000}

};


for(i = 0; i< 4; i++) //Loop scanning 4*4 matrix buttons

{

for(j = 0; j < 4; j++)

{

if(backup[i][j] != KeySta[i][j]) //Detection matrix action

{

if(backup[i][j] != 0) //Execute action when the matrix is ​​pressed

{

KeyAction(KeyCodeMap[i][j]); //Call key action function

}

backup[i][j] = KeySta[i][j]; //Refresh the previous backup value

}   

if(KeyDownTime[i][j] > 0) //Detection and execution of fast input

{

if(KeyDownTime[i][j] >= Timethr[i][j])

{    //Execute an action when the threshold is reached

KeyAction(KeyCodeMap[i][j]); //Call key action function

Timethr[i][j] += 200; //The time threshold increases by 200ms for the next execution

}

}

else //Reset threshold time when the button pops up                                                                                                                                                                                                                                                                                                                                                                                            

{

Timethr[i][j] = 1000; //Restore the initial threshold time of 1s

}

}

}

}


//Key action function, perform corresponding operations according to the key code, keycode is the key code

void KeyAction(unsigned char keycode)

{

if(keycode == 0x26) //Press the up button to increase the countdown setting value

{

if(CountDown < 9999) //Maximum timer is 9999 seconds

{

CountDown++;

Shownumber(CountDown);

}

}

if(keycode == 0x28) //Press the down button to decrease the countdown setting value

{

if(CountDown > 1) //Minimum time is one second

{

CountDown--;

Shownumber(CountDown);

}

}

if(keycode == 0x0D) //Enter key, start countdown

{

   flagStart = 1; //Start countdown

}

if(keycode == 0x1B) //ESC key, cancel countdown

{

flagStart = 0; //Stop countdown

LedBuff[6] = 0xFF; // Turn off the independent LED

enBuzz = 0; //Turn off the buzzer

CountDown =0; //Countdown returns to zero

Shownumber(CountDown);

}

}

//T0 interrupt service function, complete digital tube, key scanning and second timing

void InerruptTimer0() interrupt 1

{

static unsigned int tmr1ms = 0; //1s timer

TH0 = T0RH; //Reload the reload value

TL0 = T0RL;

if(enBuzz == 1)

{

BUZZ = ~BUZZ; //Drive the buzzer to sound

}

else

BUZZ = 1; //Turn off the buzzer


Ledscan(); //Led scan display

Keyscan(); //Key scan


if(flagStart) //Process 1 second timing when countdown starts

{

tmr1ms++;

if(tmr1ms >= 1000)

{

tmr1ms = 0;

flag1s = 1;

}

}  

else //When the countdown is not started, the 1 second timer is reset to zero

{

tmr1ms = 0;

}


}


//LED dynamic scanning function, needs to be called in the timer interrupt

[1] [2]
Reference address:[Self-study 51 MCU] 10 -- PWM introduction, 51 MCU RAM area division

Previous article:[Self-study 51 single chip microcomputer] 12 --- Preliminary understanding of 1602 LCD
Next article:[Self-study 51 single-chip microcomputer] 9 -- Stepper motor principle, buzzer principle, single-chip microcomputer IO

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号