Custom "bits" and their storage scheme in C51 programming

Publisher:chaochenLatest update time:2013-02-17 Source: 21IC Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

  introduction

  In existing textbooks and related articles, the concept of saving the status of custom "bits" in microcontroller C language programming is rarely mentioned.

  When the concept of "bit" is mentioned in C language programming of single-chip microcomputers, people will naturally think of the two user general flag bits F0 of PSW.5 and F1 of PSW.1 in the status word PSW. These two flag bits can participate in Boolean operations and "bit" control operations, and can also be saved with the status word PSW. However, this point is often overlooked: in some specific cases, such as in the interrupt service program programmed in C language, the operation of the two user flag bits F0 of PSW.5 and F1 of PSW.1 in the status word PSW may be invalid. For example:

  void EX1_ISR() interrupt 2 {//External interrupt 1

  static unsigned int tempaddr; //define the receiving address cache

  static unsigned int tempkey; //define receive data cache

  unsigned int timecnt;

  timecnt=TH1*256+TL1;

  TH1=0;

  TL1=0;

  TR1=1; //Timer 1 starts

  F0=~F0; //Invert F0

  if(F0) {

  tempaddr=tempaddr<<1;

  }

  else {

  tempkey=tempkey<<1;

  }

  }

  The above is an interrupt service program for the external interrupt 1 of the microcontroller. At first glance, it seems that there is no problem, and it can be "edited" during simulation debugging. But in fact, this is an incorrect program - the "inversion" operation of the "F0" user flag bit cannot achieve its expected effect. Because the "inversion" operation of the "F0" user flag bit is performed in the interrupt service program. When entering the interrupt, the C language will automatically protect the "interrupt scene" - push the program pointer PC, accumulator ACC, status word PSW, etc. into the stack for protection... until the interrupt returns, the stack is popped out and the variable value during the interrupt service is overwritten, and it is restored to the original state before the stack was pushed. Therefore, F0 in the status word PSW is no exception. If F0 is in the logical "0" state before being pushed into the stack, it will still be restored to the logical "0" state after the interrupt returns - no matter how the inversion is changed in the interrupt service program - that is, the operation of trying to change the value of F0 in the interrupt service program is biased. For the interrupt service program mentioned above, if the initial state of F0 is logic "0", that is, it is always logic "0" before entering the interrupt service and after the interrupt returns, then after entering the execution of the "F0=~F0" instruction, F0 is always logic "1", so the next instruction to be executed is the "tempaddr=tempaddr<<1;" instruction in the curly braces under "if(F0)", and the "tempkey=tempkey<<1" instruction in the curly braces under "else" will never be executed. Therefore, if the interrupt service program is to achieve the expected effect - the instructions in the curly braces under "if(F0)" and the instructions in the curly braces under "else" are run in turn, a custom flag bit that is not affected by interrupt scene protection, etc. must be set.

  1. Saving of custom flag "bit"

  In C language programming, the use of custom flags is very likely, and some programs may have many custom flags, and some of them may have to be saved. For example, some control devices maintain some control states, and even if the power is turned on again after a power outage, the control state can still remain unchanged - this involves the issue of preservation.

  Example 2: We once made a wireless remote control device for raising and lowering the laser projection screen. This control device with a single-chip microcomputer as the core and the scrolling motor for raising and lowering the screen are all installed and fixed in a narrow iron barrel with a diameter of less than 50 mm, so it is very troublesome to install or remove it. In order to succeed at one time - to avoid the trouble of disassembling and installing again, I deliberately used a custom flag bit when programming in C language - the flip flag bit "switch_sign". Because the key signs of the up "▲", pause "■", and down "▼" on the wireless remote control handle are already fixed, therefore, if due to wiring errors, the projection screen rolls up when the down "▼" key is pressed, and the projection screen extends downward when the up "▲" key is pressed... With the custom flag bit "switch_sign", there is no need to worry about these. The relevant C language program segment is as follows:

  #defineuint unsigned int

  #defineuchar unsigned char

  uint Decode_addr, Decode_key, addr;

  sbit JD1_out=P0^4; //define relay 1 control output terminal

  sbit JD2_out=P0^5; //define relay 2 control output terminal

  sbit BEEP=P0^3; //define beep sound output

  bit bdata switch_sign; //Custom flip flag (should be defined as a global variable)

  void Telecontrol_Data() {

  …

  if(Decode_addr==0x5535) {//Address code check

  if(Decode_key==0x00C0) {//“▲” key code check

  BEEP=1; //Buzzer sound output

  if(switch_sign) {//Flip the flag

  JD1_out=0; //Relay 1 control output

  JD2_out=1; //Relay 2 control output

  }

  else {

  JD1_out=1; //Relay 1 control output

  JD2_out=0; //Relay 2 control output

  }

  }

  if(Decode_key==0x0030) {//“■” key code check

  BEEP=1; //Buzzer sound output

  JD1_out=0; //Relay 1 control output

  JD2_out=0; //Relay 2 control output

  }[page]

  if(Decode_key==0x000C) {//“▼” key code check

  BEEP=1; //Buzzer sound output

  if(switch_sign) {//Flip the flag

  JD1_out=1; //Relay 1 control output

  JD2_out=0; //Relay 2 control output

  }

  else {

  JD1_out=0; //Relay 1 control output

  JD2_out=1; //Relay 2 control output

  }

  }

  }

  if(Decode_addr==0x5D35) {//Address code verification when negating the operation

  if(Decode_key==0x00C0) {//“▲” key code check

  BEEP=1; //Buzzer sound output

  switch_sign=~switch_sign; //Invert the flip flag

  save_data(); //Call the subroutine to save data

  }

  }

  }

  From the above remote control data processing subroutine, we can see that at any time, only one of the control output terminals JD1_out and JD2_out of the two relays can be turned on. When the remote control "▲" key is pressed effectively, the logic "0" or logic "1" state of the flip flag "switch_sign" will determine whether the control output terminals JD1_out and JD2_out of the two relays are turned on and off, or turned off and on; similarly, when the remote control "▼" key is pressed effectively, the same effect opposite to the "▲" key will be obtained... In other words, as long as the logic state of the flip flag "switch_sign" is changed, the control output state of which of the two relay control output terminals is "on" and which is "off" can be changed. That is, when the same remote control button is pressed (such as the "▲" key is pressed), the logic state of the flag "switch_sign" is different, and the control output state of which of the two relay control output terminals is "on" and which is "off" will also be different. The buzzer sound indicates whether the key operation is valid.

  The power motor for lifting the projection screen is an AC 220V AC motor. Figure 1 is a schematic diagram of the motor control circuit. It can be seen that when the relay JD1 is closed and JD2 is disconnected, L1 in the motor M is the main winding and L2 is the starter auxiliary winding, and the motor will run in one direction; when the relay JD1 is disconnected and JD2 is closed, L1 in the motor M is the starter auxiliary winding and L2 is the main winding, and the motor will run in the opposite direction of the original. Combined with the above, change the logical state of the flip flag "switch_sign" → change the control output state of the two relay control output terminals, which is "on" and which is "off" → change the running direction of the motor → the lifting state of the projection screen. In other words, changing the logical state of the flip flag "switch_sign" can correct the running direction of the remote control motor and the lifting state of the projection screen. After coordinating the corresponding relationship between the remote control button and the lifting of the projection screen, the current logical state of the custom flag "switch_sign" must be saved, otherwise, the next power-on reset initialization after power failure may make a fool of yourself again.

  From the program in Example 2, we can also see that the inversion operation of the flip flag "switch_sign" is also performed using the "▲" key on the same remote control, but the address code of the remote control has been tampered with a little bit - the address code is changed (0x5D35), and then changed back to the original address code (0x5535) after the corresponding operation is coordinated.

  2 Save 1 byte to restore the custom flag "bit"

  There are many ways to save and restore a custom flag "bit". I have tried several methods. Example 3 is a method of saving 1 byte to restore a custom flag bit. The specific operation is as follows:

  static unsigned char current_dat; //define a general auxiliary byte variable

  bit bdata switch_sign; //Custom flip flag (should be defined as a global variable)

  …

  switch_sign=~switch_sign; // invert the sign bit

  if(switch_sign) {//Judge whether switch_sign is logic "1" or logic "0"

  current_dat=0xA5; //Assign value to general auxiliary byte variable

  }

  else {

  current_dat=0x00; //General auxiliary byte variable

  }

  save_data(); //Call the subroutine to save data

  BEEP=1; //Buzzer sound output

  The above program is: after negating the flip flag "switch_sign", if "switch_sign" is in the logic "1" state, assign "0xA5" to the general auxiliary byte variable "current_dat" (of course, this data is set by you); if "switch_sign" is in the logic "0" state, assign "0x00" to the general auxiliary byte variable "current_dat" (this data is also set by you, as long as it is different from the previous one), and then call the data saving program to save the general auxiliary byte variable "current_dat". In this way, even if the power is off, the current state of the flip flag "switch_sign" has been indirectly saved by the general auxiliary byte variable "current_dat"... When the next power-on reset is initialized, the data of the saved auxiliary variable "current_dat" should be read out first, and restored to the corresponding logical state of the flip flag "switch_sign". When the power is turned on and the data read from the storage is "0xA5", the flip flag "switch_sign" is set to "1"; if the data read is "0x00", the flip flag "switch_sign" is set to "0" - this corresponds to the state when it was originally saved. The operation process is as shown in Example 4:

  static unsigned char current_dat; //define a general auxiliary byte variable

  static unsigned char addr; //Custom address variable buffer unit

  static unsigned char Rdat; //Custom read data buffer unit

  bit bdata switch_sign; //Custom flip flag (should be defined as a global variable)

  ……[page]

  addr=0x7F6; //Give an original storage address

  REEPROM(); //Call the subroutine to read E2PROM

  current_dat=Rdat; //Return the read data to the general auxiliary byte variable

  if(current_dat==0xA5) {//Judge whether the read data is equal to "0xA5"

  switch_sign=1; //Set the flip flag "switch_sign" to "1"

  }

  else {

  switch_sign=0; //Set the flip flag "switch_sign" to "0"

  }

  31 bytes to hold 8 custom "bits"

  The process of restoring a custom flag bit by saving a custom byte variable has been described above. Next, the solution of saving 8 custom "bits" with a byte variable is described. There are many solutions for saving 8 custom "bits" with a byte variable. Example 5 is a more ideal one:

  #defineuint unsigned int

  #defineuchar unsigned char

  uintaddr;

  ucharWdat, Rdat;

  uchar bdatacurrent_dat; //define the byte variable current_dat of unsigned char type in the bit-addressable area

  sbitsign_bit1 = current_dat^0; //Use the keyword sbit to define a bit variable to independently access 1 bit in the addressable bit object

  sbitsign_bit2 = current_dat^1; //Customized flag bit 2

  sbitsign_bit3 = current_dat^2; //Customized flag bit 3

  …

  sbitsign_bit8 = current_dat^7; //Customized flag bit 8

  …

  void Bit_save() {//Custom flag bit save subroutine

  addr = 0x7F6; // give storage address

  Wdat = current_dat; // assign current_dat to the buffer unit Wdat of writing E2PROM

  save_data(); //Call the save subroutine to store current_dat data

  }

  void Bit_comeback() {//Custom flag bit reset subroutine

  addr=0x7F6; //Give an original storage address

  REEPROM(); //Call the subroutine to read E2PROM

  current_dat=Rdat;

  //Return the read data to the general auxiliary byte variable

  }

  The above program may be the simplest solution for custom bit operations and their storage. First, define a general byte variable current_dat of ucsigned char type in the bit-addressable area, and then use the keyword "sbit" to define a bit variable to independently access one of the addressable bit objects. In this way, the custom flag bit is raised to a bit-accessible mode similar to that in the special function register (SFR) - the 8 bits in the byte variable current_dat can be operated independently, and its storage or reading and restoration can be done by directly saving or reading the byte variable current_dat, without the need for auxiliary operations such as logical AND, logical OR, etc. as in other solutions.

  Conclusion

  It is not necessary to have custom flags in C language programming of single-chip microcomputers, but in some cases, using custom flags will make the whole program appear concise and bright. Of course, the preservation of custom flags depends on the specific situation - it should be said that it is a last resort.

Reference address:Custom "bits" and their storage scheme in C51 programming

Previous article:Transplantation of μC/OS-II on C8051F series MCU
Next article:PLC and multi-machine communication based on RS485 interface Modbus protocol

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号