3
\$\begingroup\$

I am trying to run following code on AT89C2051, using Keil for compiling and programming hex file with Superpro.

#include <reg51.h>  

// Define a delay function
void delay_ms(unsigned int milliseconds) {
  unsigned int i, j;
  for (i = 0; i < milliseconds; i++) {
    for (j = 0; j < 1275; j++) { // Approximate delay, adjust based on clock frequency
      // Delay loop
    }
  }
}

// Main function
void main() {
  while (1) {
    // Turn the LED on (assuming LED is connected to P0.0)
    P1 = 0x00; // Set P1 to 0 (low voltage) to turn the LED on
    delay_ms(500); // Delay for 500 milliseconds

    // Turn the LED off
    P1 = 0xFF; // Set P1 to FF (high voltage) to turn the LED off
    delay_ms(500); // Delay for 500 milliseconds
  }
}

The code never works I suspect it is not getting programmed correctly. Please tell me what is the correct procedure to program this microcontroller.

Following is the procedure that I am following.

  1. Compile above I/O toggling code in Keil with device AT89C2051 and clock 11.0592MHz selected.

  2. Generated hex file is loaded into superpro610p. During load buffer I tried both binary and intel format option in Superpro.

  3. Programmed MCU with loaded buffer.

  4. No toggle appears on any pin of MCU.

  5. Programmer Link

  6. HEX output file generated by Keil.

    :0300000002083DB6
    :0C083D00787FE4F6D8FD75810702082FD3
    :10080000900000AF82AE83E4FCFDFBFA7901F8D3DF
    :090810001208194003A380EB2239
    :0E082F00E4F5901208007590FF12080080F2A8
    :10081900EB9FF5F0EA9E42F0E99D42F0EC6480C856
    :0608290064809845F022F6
    :00000001FF
    
  7. Startup.lst file generated by Keil.

     A51 MACRO ASSEMBLER  STARTUP                                                              06/11/2025 10:53:16 PAGE     1
    
    
     MACRO ASSEMBLER A51 V8.2.7.0
     OBJECT MODULE PLACED IN .\Objects\STARTUP.obj
     ASSEMBLER INVOKED BY: C:\Keil_v5\C51\BIN\A51.EXE STARTUP.A51 SET(SMALL) PRINT(.\Listings\STARTUP.lst) OBJECT(.\Objects\S
                           TARTUP.obj) EP
    
     LOC  OBJ            LINE     SOURCE
    
                            1     $nomod51 
                            2     ;------------------------------------------------------------------------------
                            3     ;  This file is part of the C51 Compiler package
                            4     ;  Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
                            5     ;  Version 8.01
                            6     ;
                            7     ;  *** <<< Use Configuration Wizard in Context Menu >>> ***
                            8     ;------------------------------------------------------------------------------
                            9     ;  STARTUP.A51:  This code is executed after processor reset.
                           10     ;
                           11     ;  To translate this file use A51 with the following invocation:
                           12     ;
                           13     ;     A51 STARTUP.A51
                           14     ;
                           15     ;  To link the modified STARTUP.OBJ file to your application use the following
                           16     ;  Lx51 invocation:
                           17     ;
                           18     ;     Lx51 your object file list, STARTUP.OBJ  controls
                           19     ;
                           20     ;------------------------------------------------------------------------------
                           21     ;
                           22     ;  User-defined <h> Power-On Initialization of Memory
                           23     ;
                           24     ;  With the following EQU statements the initialization of memory
                           25     ;  at processor reset can be defined:
                           26     ;
                           27     ; <o> IDATALEN: IDATA memory size <0x0-0x100>
                           28     ;     <i> Note: The absolute start-address of IDATA memory is always 0
                           29     ;     <i>       The IDATA space overlaps physically the DATA and BIT areas.
       0080                30     IDATALEN        EQU     80H
                           31     ;
                           32     ; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF> 
                           33     ;     <i> The absolute start address of XDATA memory
       0000                34     XDATASTART      EQU     0     
                           35     ;
                           36     ; <o> XDATALEN: XDATA memory size <0x0-0xFFFF> 
                           37     ;     <i> The length of XDATA memory in bytes.
       0000                38     XDATALEN        EQU     0      
                           39     ;
                           40     ; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF> 
                           41     ;     <i> The absolute start address of PDATA memory
       0000                42     PDATASTART      EQU     0H
                           43     ;
                           44     ; <o> PDATALEN: PDATA memory size <0x0-0xFF> 
                           45     ;     <i> The length of PDATA memory in bytes.
       0000                46     PDATALEN        EQU     0H
                           47     ;
                           48     ;</h>
                           49     ;------------------------------------------------------------------------------
                           50     ;
                           51     ;<h> Reentrant Stack Initialization
                           52     ;
                           53     ;  The following EQU statements define the stack pointer for reentrant
                           54     ;  functions and initialized it:
                           55     ;
                           56     ; <h> Stack Space for reentrant functions in the SMALL model.
                           57     ;  <q> IBPSTACK: Enable SMALL model reentrant stack
     A51 MACRO ASSEMBLER  STARTUP                                                              06/11/2025 10:53:16 PAGE     2
    
                           58     ;     <i> Stack space for reentrant functions in the SMALL model.
       0000                59     IBPSTACK        EQU     0       ; set to 1 if small reentrant is used.
                           60     ;  <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
                           61     ;     <i> Set the top of the stack to the highest location.
       0100                62     IBPSTACKTOP     EQU     0xFF +1     ; default 0FFH+1  
                           63     ; </h>
                           64     ;
                           65     ; <h> Stack Space for reentrant functions in the LARGE model.      
                           66     ;  <q> XBPSTACK: Enable LARGE model reentrant stack
                           67     ;     <i> Stack space for reentrant functions in the LARGE model.
       0000                68     XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
                           69     ;  <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
                           70     ;     <i> Set the top of the stack to the highest location.
       0000                71     XBPSTACKTOP     EQU     0xFFFF +1   ; default 0FFFFH+1 
                           72     ; </h>
                           73     ;
                           74     ; <h> Stack Space for reentrant functions in the COMPACT model.    
                           75     ;  <q> PBPSTACK: Enable COMPACT model reentrant stack
                           76     ;     <i> Stack space for reentrant functions in the COMPACT model.
       0000                77     PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
                           78     ;
                           79     ;   <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
                           80     ;     <i> Set the top of the stack to the highest location.
       0100                81     PBPSTACKTOP     EQU     0xFF +1     ; default 0FFH+1  
                           82     ; </h>
                           83     ;</h>
                           84     ;------------------------------------------------------------------------------
                           85     ;
                           86     ;  Memory Page for Using the Compact Model with 64 KByte xdata RAM
                           87     ;  <e>Compact Model Page Definition
                           88     ;
                           89     ;  <i>Define the XDATA page used for PDATA variables. 
                           90     ;  <i>PPAGE must conform with the PPAGE set in the linker invocation.
                           91     ;
                           92     ; Enable pdata memory page initalization
       0000                93     PPAGEENABLE     EQU     0       ; set to 1 if pdata object are used.
                           94     ;
                           95     ; <o> PPAGE number <0x0-0xFF> 
                           96     ; <i> uppermost 256-byte address of the page used for PDATA variables.
       0000                97     PPAGE           EQU     0
                           98     ;
                           99     ; <o> SFR address which supplies uppermost address byte <0x0-0xFF> 
                          100     ; <i> most 8051 variants use P2 as uppermost address byte
       00A0               101     PPAGE_SFR       DATA    0A0H
                          102     ;
                          103     ; </e>
                          104     ;------------------------------------------------------------------------------
                          105     
                          106     ; Standard SFR Symbols 
       00E0               107     ACC     DATA    0E0H
       00F0               108     B       DATA    0F0H
       0081               109     SP      DATA    81H
       0082               110     DPL     DATA    82H
       0083               111     DPH     DATA    83H
                          112     
                          113                     NAME    ?C_STARTUP
                          114     
                          115     
                          116     ?C_C51STARTUP   SEGMENT   CODE
                          117     ?STACK          SEGMENT   IDATA
                          118     
     ----                 119                     RSEG    ?STACK
     0000                 120                     DS      1
                          121     
                          122                     EXTRN CODE (?C_START)
                          123                     PUBLIC  ?C_STARTUP
     A51 MACRO ASSEMBLER  STARTUP                                                              06/11/2025 10:53:16 PAGE     3
    
                          124     
     ----                 125                     CSEG    AT      0
     0000 020000   F      126     ?C_STARTUP:     LJMP    STARTUP1
                          127     
     ----                 128                     RSEG    ?C_C51STARTUP
                          129     
     0000                 130     STARTUP1:
                          131     
                          132     IF IDATALEN <> 0
     0000 787F            133                     MOV     R0,#IDATALEN - 1
     0002 E4              134                     CLR     A
     0003 F6              135     IDATALOOP:      MOV     @R0,A
     0004 D8FD            136                     DJNZ    R0,IDATALOOP
                          137     ENDIF
                          138     
                          139     IF XDATALEN <> 0
                                                  MOV     DPTR,#XDATASTART
                                                  MOV     R7,#LOW (XDATALEN)
                                    IF (LOW (XDATALEN)) <> 0
                                                  MOV     R6,#(HIGH (XDATALEN)) +1
                                    ELSE
                                                  MOV     R6,#HIGH (XDATALEN)
                                    ENDIF
                                                  CLR     A
                                  XDATALOOP:      MOVX    @DPTR,A
                                                  INC     DPTR
                                                  DJNZ    R7,XDATALOOP
                                                  DJNZ    R6,XDATALOOP
                                  ENDIF
                          153     
                          154     IF PPAGEENABLE <> 0
                                                  MOV     PPAGE_SFR,#PPAGE
                                  ENDIF
                          157     
                          158     IF PDATALEN <> 0
                                                  MOV     R0,#LOW (PDATASTART)
                                                  MOV     R7,#LOW (PDATALEN)
                                                  CLR     A
                                  PDATALOOP:      MOVX    @R0,A
                                                  INC     R0
                                                  DJNZ    R7,PDATALOOP
                                  ENDIF
                          166     
                          167     IF IBPSTACK <> 0
                                  EXTRN DATA (?C_IBP)
    
                                                  MOV     ?C_IBP,#LOW IBPSTACKTOP
                                  ENDIF
                          172     
                          173     IF XBPSTACK <> 0
                                  EXTRN DATA (?C_XBP)
    
                                                  MOV     ?C_XBP,#HIGH XBPSTACKTOP
                                                  MOV     ?C_XBP+1,#LOW XBPSTACKTOP
                                  ENDIF
                          179     
                          180     IF PBPSTACK <> 0
                                  EXTRN DATA (?C_PBP)
                                                  MOV     ?C_PBP,#LOW PBPSTACKTOP
                                  ENDIF
                          184     
     0006 758100   F      185                     MOV     SP,#?STACK-1
                          186     
                          187     ; This code is required if you use L51_BANK.A51 with Banking Mode 4
                          188     ;<h> Code Banking
                          189     ; <q> Select Bank 0 for L51_BANK.A51 Mode 4
     A51 MACRO ASSEMBLER  STARTUP                                                              06/11/2025 10:53:16 PAGE     4
    
                          190     
    
    
    
    
                          195     ;</h>
     0009 020000   F      196                     LJMP    ?C_START
                          197     
                          198                     END
     A51 MACRO ASSEMBLER  STARTUP                                                              06/11/2025 10:53:16 PAGE     5
    
     SYMBOL TABLE LISTING
     ------ ----- -------
    
    
     N A M E             T Y P E  V A L U E   ATTRIBUTES
    
     ?C_C51STARTUP. . .  C SEG    000CH       REL=UNIT
     ?C_START . . . . .  C ADDR   -----       EXT
     ?C_STARTUP . . . .  C ADDR   0000H   A   
     ?STACK . . . . . .  I SEG    0001H       REL=UNIT
     ACC. . . . . . . .  D ADDR   00E0H   A   
     B. . . . . . . . .  D ADDR   00F0H   A   
     DPH. . . . . . . .  D ADDR   0083H   A   
     DPL. . . . . . . .  D ADDR   0082H   A   
     IBPSTACK . . . . .  N NUMB   0000H   A   
     IBPSTACKTOP. . . .  N NUMB   0100H   A   
     IDATALEN . . . . .  N NUMB   0080H   A   
     IDATALOOP. . . . .  C ADDR   0003H   R   SEG=?C_C51STARTUP
     PBPSTACK . . . . .  N NUMB   0000H   A   
     PBPSTACKTOP. . . .  N NUMB   0100H   A   
     PDATALEN . . . . .  N NUMB   0000H   A   
     PDATASTART . . . .  N NUMB   0000H   A   
     PPAGE. . . . . . .  N NUMB   0000H   A   
     PPAGEENABLE. . . .  N NUMB   0000H   A   
     PPAGE_SFR. . . . .  D ADDR   00A0H   A   
     SP . . . . . . . .  D ADDR   0081H   A   
     STARTUP1 . . . . .  C ADDR   0000H   R   SEG=?C_C51STARTUP
     XBPSTACK . . . . .  N NUMB   0000H   A   
     XBPSTACKTOP. . . .  N NUMB   0000H   A   
     XDATALEN . . . . .  N NUMB   0000H   A   
     XDATASTART . . . .  N NUMB   0000H   A   
    
    
     REGISTER BANK(S) USED: 0 
    
    
     ASSEMBLY COMPLETE.  0 WARNING(S), 0 ERROR(S)
    
  8. Another lst file in the project.

C51 COMPILER V9.60.7.0   CODE                                                              06/11/2025 14:25:16 PAGE 1   


C51 COMPILER V9.60.7.0, COMPILATION OF MODULE CODE
OBJECT MODULE PLACED IN .\Objects\CODE.obj
COMPILER INVOKED BY: C:\Keil_v5\C51\BIN\C51.EXE CODE.C OPTIMIZE(8,SPEED) PRINT(.\Listings\CODE.lst) TABS(2) OBJECT(.\Obj
                    -ects\CODE.obj)

line level    source

   1          #include <reg51.h> 
   2          #include <intrins.h>
   3          int x=0;
   4          // Define a delay function
   5          void delay_ms(unsigned int milliseconds) {
   6   1        unsigned int i, j;
   7   1        unsigned int x=0;
   8   1        for (i = 0; i < milliseconds; i++) {
   9   2          for (j = 0; j < 1275; j++) { // Approximate delay, adjust based on clock frequency
  10   3            _nop_();
  11   3          }
  12   2        }
  13   1      }
  14          
  15          // Main function
  16          void main() {
  17   1        while (1) {
  18   2          // Turn the LED on (assuming LED is connected to P0.0)
  19   2          P1 = 0x00; // Set P1 to 0 (low voltage) to turn the LED on
  20   2          delay_ms(500); // Delay for 500 milliseconds
  21   2      
  22   2          // Turn the LED off
  23   2          P1 = 0xFF; // Set P1 to FF (high voltage) to turn the LED off
  24   2          delay_ms(500); // Delay for 500 milliseconds
  25   2        }
  26   1      }


MODULE INFORMATION:   STATIC OVERLAYABLE
   CODE SIZE        =     55    ----
   CONSTANT SIZE    =   ----    ----
   XDATA SIZE       =   ----    ----
   PDATA SIZE       =   ----    ----
   DATA SIZE        =      2       2
   IDATA SIZE       =   ----    ----
   BIT SIZE         =   ----    ----
END OF MODULE INFORMATION.


C51 COMPILATION COMPLETE.  0 WARNING(S),  0 ERROR(S)

  1. m51 file in the project folder.
BL51 BANKED LINKER/LOCATER V6.22.4.0                                                    06/11/2025  14:25:16  PAGE 1


BL51 BANKED LINKER/LOCATER V6.22.4.0, INVOKED BY:
C:\KEIL_V5\C51\BIN\BL51.EXE .\Objects\STARTUP.obj, .\Objects\CODE.obj TO .\Objects\AMMETER PRINT (.\Listings\AMMETER.m51
>> )


MEMORY MODEL: SMALL


INPUT MODULES INCLUDED:
  .\Objects\STARTUP.obj (?C_STARTUP)
  .\Objects\CODE.obj (CODE)
  C:\KEIL_V5\C51\LIB\C51S.LIB (?C_INIT)


LINK MAP OF MODULE:  .\Objects\AMMETER (?C_STARTUP)


            TYPE    BASE      LENGTH    RELOCATION   SEGMENT NAME
            -----------------------------------------------------

            * * * * * * *   D A T A   M E M O R Y   * * * * * * *
            REG     0000H     0008H     ABSOLUTE     "REG BANK 0"
            DATA    0008H     0002H     UNIT         ?DT?CODE
            DATA    000AH     0002H     UNIT         _DATA_GROUP_
            IDATA   000CH     0001H     UNIT         ?STACK

            * * * * * * *   C O D E   M E M O R Y   * * * * * * *
            CODE    0000H     0003H     ABSOLUTE     
                    0003H     07FDH                  *** GAP ***
            CODE    0800H     008CH     UNIT         ?C_C51STARTUP
            CODE    088CH     0025H     UNIT         ?PR?_DELAY_MS?CODE
            CODE    08B1H     0012H     UNIT         ?PR?MAIN?CODE
            CODE    08C3H     0005H     UNIT         ?C_INITSEG



OVERLAY MAP OF MODULE:   .\Objects\AMMETER (?C_STARTUP)


SEGMENT                          DATA_GROUP 
  +--> CALLED SEGMENT          START    LENGTH
----------------------------------------------
?C_C51STARTUP                  -----    -----
  +--> ?PR?MAIN?CODE
  +--> ?C_INITSEG

?PR?MAIN?CODE                  -----    -----
  +--> ?PR?_DELAY_MS?CODE

?PR?_DELAY_MS?CODE             000AH    0002H

******************************************************************************
* RESTRICTED VERSION WITH 0800H BYTE CODE SIZE LIMIT; USED: 004AH BYTE ( 3%) *
******************************************************************************

Program Size: data=13.0 xdata=0 code=203
LINK/LOCATE RUN COMPLETE.  0 WARNING(S),  0 ERROR(S)

\$\endgroup\$
33
  • \$\begingroup\$ you don't "burn hex files"; you load ("flash") a binary. "hex" is just short for "hexabinary" and that just is a method of printing numbers. \$\endgroup\$ Commented Jun 10 at 15:09
  • 1
    \$\begingroup\$ @MarcusMüller In the era of 8051s, the terminology really was to burn binaries into ROMs or Flash even. And hex file means a binary in Intel HEX format. To me, the terminology or what it means is valid, and understandable, even if I might not use the word burn, but I may use the words hex file daily to refer to the compiled binary. \$\endgroup\$ Commented Jun 10 at 16:56
  • \$\begingroup\$ Okay I corrected that too. But my question is still there. How do I get my MCU programmed and get the blinking work. \$\endgroup\$ Commented Jun 10 at 17:07
  • \$\begingroup\$ you could use something like this ceptimus.co.uk/index.php/2016/02/06/… Note that you need a ~13.5V programming voltage. The AT89S2051/4051 need only 5 V. \$\endgroup\$ Commented Jun 10 at 17:15
  • 1
    \$\begingroup\$ As a next step, your programmer should be able to verify that the MCU's flash contains the binary you flashed before. Please check that. \$\endgroup\$ Commented Jun 11 at 5:44

2 Answers 2

2
\$\begingroup\$

Reason of Code Located at 0x800

Apparently you are using the evaluation version of the development kit.

The relevant page "Limitations" lists (among others) this restriction:

C51 Evaluation Tools

  • Programs start at offset 0x0800. Programs generated with the evaluation software may not be programmed into single-chip devices with less than 2 Kbytes of on-chip ROM.

There is no way around it. So you need to buy a license and install it, if you urgently want to use Keil C51.

Or you use another compiler (and editor/IDE). Unfortunately (for you) recommendations are off-topic here, but if you use your web fu with "open source c compiler for 8051", I'm sure you will find some suitable compiler system.


Reason of Code Execution Error

The data sheet documents that the MCU has only 2K of flash ROM, see chapter 7 on page 6. The address range is 0x0000 to 0x07FF.

The MCU starts execution at address 0. But the bytes of the provided binary at that address (02083D) form an absolute jump to 0x083d. The data sheet says about such instructions:

Violating the physical space limits may cause unknown program behavior.

And

Again, violating the memory boundaries may cause erratic execution.

\$\endgroup\$
-2
\$\begingroup\$

Your system probably just does what you told it to.

Your code does not contain a delay function:

// Define a delay function
void delay_ms(unsigned int milliseconds) {
  unsigned int i, j;
  for (i = 0; i < milliseconds; i++) {
    for (j = 0; j < 1275; j++) { // Approximate delay, adjust based on clock frequency
      // Delay loop
    }
  }
}

The job of your C compiler is the following:

  1. Read C code, make syntactical understanding (i.e., understand what a function is, convert statements like i += 7 into "there's a variable i, and it gets a new value, and the new value is the result of the operation + applied to the variable i and an immediate value, 7", …)
  2. model what the so-called (by the standard) "abstract C machine" would do based on that code, i.e., make a behavioural model of your code according to a well-defined theoretical computer. That asks the following questions:
    1. "given the rules of the C language, what is result calculated by each function?" (there's no result here)
    2. "given the memory model of the C language, and the memory locations outside of sole control of the function, what about the rest of the environment / memory does this function change, after it's run completely?" (there's no side effects / changes to memory here; and just counting up a memory value, for example, can be done by a single update, instead of 1275 steps, because the question is after it's run, not at every tiny step in the source code.)
  3. implement that behaviour by generating machine code for your target computer (here: the CPU of the AT89C2051).

Your loop doesn't actually calculate anything that becomes externally visible. Hence, the effect on the abstract C machine of calling delay_ms(1000) would be the same as doing nothing. So, the compiler, correctly understanding your code says "oh this function calculates no value and has no side effects, let's just remove it". This is valid. This is how your compiler knows that unsigned int A = …; A = A + A is the same as A *= 2 is the same as A << 1, and that it knows how to put into machine code.

So, your code really doesn't contain a delay, when compiled. (rich.g.william's delay loop code doesn't either, i = i also has no effects and hence "compiles away", even without compiler optimizations; this is the typical "but I can trick the compiler into doing what I want" magical thinking that luckily has little to do with how C compilers or the C language work.)

The side-effect of "wasting cycles" is something you need to explicitly tell, in your C code, you want to preserve – there's no shortcut there. Any version of your delay loop that doesn't actually change anything every loop iteration is actually a null operation for the abstract C machine, and will get optimized away. And that is fine, because you want your C code in general to be correct and fast, and the rumor that C is "just high-level syntax for assembler" simply hasn't been true for maybe 30, 40 years.

You'll, in actual standard libraries for microcontrollers, find such wait loops often implemented in straight inline assembler. That actually gives you the freedom to "count cycles" (you don't know what, even if they do something, your for loops get compiled to, it might change depending on e.g. how many registers the code surrounding them needs). In your case, try with an inline assembly NOP where you just say // Delay Loop.

\$\endgroup\$
17
  • \$\begingroup\$ I added _nop_(); in the delay loop and still no toggling. \$\endgroup\$ Commented Jun 11 at 9:29
  • \$\begingroup\$ I don't know what _nop_() is, but if it's not doing observable side effects, you've won nothing. I think the term "inline assembly" was clear enough. \$\endgroup\$ Commented Jun 11 at 10:22
  • \$\begingroup\$ Sidk, you must find assembler in the list file, there was nothing in there, not even a mention of P1 \$\endgroup\$ Commented Jun 11 at 10:31
  • \$\begingroup\$ Marcus my little bit of code wasn't meant to work just to give Sidk the idea of writing a tiny bit of code that's easy to find in the list file, and it compiles fine in VS 2022 \$\endgroup\$ Commented Jun 11 at 10:33
  • \$\begingroup\$ @Sidk Use your own C++ code it was fine, you are very close to finding out what's wrong now, just will be something very small wrong now \$\endgroup\$ Commented Jun 11 at 10:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.