Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Is this code correct ?

Status
Not open for further replies.

Okada

Banned
Joined
Jun 16, 2016
Messages
1,159
Helped
129
Reputation
252
Reaction score
129
Trophy points
63
Activity points
0
I want to know whether the information provided here is correct.

https://www.microcontrollerboard.com/pic_serial_communication.html

I am using this code but I don't see any data on UART. UART is not working at all.

I am using PIC16F877A with 4 MHz Crystal

_XTAL_FREQ is defined as 4000000


Code C - [expand]
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
void UART1_Init(unsigned int baudrate) {
    //SPBRG value for high baudrate
    SPBRG = ((_XTAL_FREQ) / (baudrate * 16)) - 1;
    BRGH_bit = 1;  //setting high baudrate
    SYNC_bit = 0;  //setting Asynchronous mode for UART
    SPEN_bit = 1;  //enable Serial Port
    CREN_bit = 1;  //enable Continuous Reception
    TXEN_bit = 1;  //enable Transmission
}
 
void UART1_Write(char data_) {
    TXREG = data_;
    while(!TRMT_bit)asm clrwdt;
}
 
void UART1_Write_Text(char *text) {
    while(*text) {
       UART1_Write(*text++);
       asm clrwdt
    }
}
 
char UART1_Read() {
    while(!RCIF_bit)asm clrwdt;
    return RCREG;
}
 
UART1_Init(9600);
Delay_ms(200);
 
 
UART_Write_Text("Hello!");



Connections are correct because I am using EasyPIC v7 development board.

If I use mikroC PRO PICs UART library functions then it is working but using the above code it is not working. Crystal frequency is XT 4 MHz.
 
Last edited:

Where is the main function ?
Even any ISR vector isn't present.
The above code seems just part of the program.
 
  • Like
Reactions: Okada

    Okada

    Points: 2
    Helpful Answer Positive Rating
I am not using ISR. I am just trying to send some string on UART. As I said if I use mikroC PRO PICs UART library functions then it works perfectly.
I found some problem. In the code posted in post #1 if I directly assign 25 for the SPBRG and compile the code then it is working fine (both transmit and receive) but if I use the formula used for SPBRG calculation then it is not working.

Here is the new formula I tried. Even this is not working.

Code:
#define F_OSC 4000000

//Inside UART1_Init() function
SPBRG = (unsigned char)(f_osc / (unsigned long)(baudrate * 16)) - 1;

This above method is not working.

Code:
SPBRG = 25;

This works perfectly.

This is the code I am using.


Code C - [expand]
1
2
3
4
5
6
7
8
9
void UART1_Init(unsigned int baudrate) {
    //SPBRG value for high baudrate
    SPBRG = (unsigned char)(F_OSC / (unsigned long)(baudrate * 16)) - 1;
    BRGH_bit = 1;  //setting high baudrate
    SYNC_bit = 0;  //setting Asynchronous mode for UART
    SPEN_bit = 1;  //enable Serial Port
    CREN_bit = 1;  //enable Continuous Reception
    TXEN_bit = 1;  //enable Transmission
}



This is the compiler generated assembly code.


Code ASM - [expand]
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
_UART1_Init:
 
;Smart Home Automation.c,67 ::                 void UART1_Init(unsigned int baudrate) {
;Smart Home Automation.c,69 ::                 SPBRG = (unsigned char)(F_OSC / (unsigned long)(baudrate * 16)) - 1;
        MOVF       FARG_UART1_Init_baudrate+0, 0
        MOVWF      R0+0
        MOVF       FARG_UART1_Init_baudrate+1, 0
        MOVWF      R0+1
        RLF        R0+0, 1
        RLF        R0+1, 1
        BCF        R0+0, 0
        RLF        R0+0, 1
        RLF        R0+1, 1
        BCF        R0+0, 0
        RLF        R0+0, 1
        RLF        R0+1, 1
        BCF        R0+0, 0
        RLF        R0+0, 1
        RLF        R0+1, 1
        BCF        R0+0, 0
        MOVF       R0+0, 0
        MOVWF      R4+0
        MOVF       R0+1, 0
        MOVWF      R4+1
        CLRF       R4+2
        CLRF       R4+3
        MOVLW      0
        MOVWF      R0+0
        MOVLW      9
        MOVWF      R0+1
        MOVLW      61
        MOVWF      R0+2
        MOVLW      0
        MOVWF      R0+3
        CALL       _Div_32x32_U+0
        DECF       R0+0, 0
        MOVWF      SPBRG
;Smart Home Automation.c,70 ::                 BRGH_bit = 1;  //setting high baudrate
        BSF        TX8_9_bit, 2
;Smart Home Automation.c,71 ::                 SYNC_bit = 0;  //setting Asynchronous mode for UART
        BCF        TX8_9_bit, 4
;Smart Home Automation.c,72 ::                 SPEN_bit = 1;  //enable Serial Port
        BSF        RC8_9_bit, 7
;Smart Home Automation.c,73 ::                 CREN_bit = 1;  //enable Continuous Reception
        BSF        RC8_9_bit, 4
;Smart Home Automation.c,74 ::                 TXEN_bit = 1;  //enable Transmission
        BSF        TX8_9_bit, 5
;Smart Home Automation.c,75 ::                 }
L_end_UART1_Init:
        RETURN
; end of _UART1_Init



I debugged the code in mikroC PRO PIC by passing 9600 to UART1_Init() function and I found that it is generating 254 instead of 25 for the SPBRG value.

See image.

- - - Updated - - -

I found some strange problem. I have attached the project. if you directly assign SPBRG value as 25 then it is working fine. If formula for SPBRG is used then it is not working.

What I found.

I am passing 9600 for UART1_Init() and the strange thing I see while debugging is baudrate variable remais 0 all the time and (baudrate * 16) is yielding 0 and F_OSC / (baudrate * 16) is giving some unexpected value and hence I am getting SPBRG = 254.

Another strange thing I see if immediately when UART1_Init() function is entered SPBRG value will be 25.

If you have demo version of mikroC PRO PIC Compiler then please open my project and Compile it and try to debug and you will see what I am telling.
 

Attachments

  • spbrg.png
    spbrg.png
    84 KB · Views: 55
  • UART Test.rar
    25.9 KB · Views: 37
Last edited:

Your problem (at least a sufficient cause to make the code fail) is not understanding basic C type conversions.

Instead of writing
Code:
(unsigned long)(baudrate * 16)

you need to write
Code:
(unsigned long)baudrate * 16

The former code is first multiplying two int numbers (with overflow) and then converting to long, result is 22528. The involves additional overflows when calculating the final result.

Your code has also the disadvantage of always rounding SPBRG value to floor instead to nearest, which might matter for some baud rates.
 

@FvM

Why this is not working ?


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void UART1_Init(unsigned int baudrate) {
    unsigned long int value_1 = 0;
    
    value_1 = baudrate * 16;
    value_1 = F_OSC / value_1;
    value_1 = value_1 - 1;
    //SPBRG value for high baudrate
    //SPBRG = (unsigned char)(F_OSC / (unsigned long)(baudrate * 16)) - 1;
    SPBRG = value_1;
    BRGH_bit = 1;  //setting high baudrate
    SYNC_bit = 0;  //setting Asynchronous mode for UART
    SPEN_bit = 1;  //enable Serial Port
    CREN_bit = 1;  //enable Continuous Reception
    TXEN_bit = 1;  //enable Transmission
}



I don't know why even though I pass 9600 which is well within the unsigned int limit baudrate variable always hold 0.


Edit:

Finally it worked. See image. I had to modify the formula usage and also I had to name the function as

Code:
UART1_Initialize()

If I use

Code:
UART1_Init()

as the name for the function then baudrate variable always remains 0. mikroC PRO PIC UART library uses this name for UART initialization function. Even though I have unchecked the UART library in library manager it is somehow clashing. I renamed the function to UART1_Initilize() and baudrate variable was filled with 9600. Later I modified the formula usage and got 25 for the SPBRG value.
 

Attachments

  • spbrg value generation.png
    spbrg value generation.png
    54.5 KB · Views: 58
Last edited:

Why this is not working ?

You have effectively this code:
Code:
unsigned int baudrate=9600;
unsigned long int value_1;
value_1 = baudrate * 16;

As already explained baudrate * 16 is performed as integer (16 bit) multiply, according to C language rules. You need to cast at least one term to long int before performing the multiply, e.g.
Code:
value_1 = (unsigned long)baudrate * 16;
 
  • Like
Reactions: Okada

    Okada

    Points: 2
    Helpful Answer Positive Rating
Finally I made this code and it is working for 9600 bps. I have not tested for other baudrates and F_OSC value> F_OSC used is 4000000. Is this code correct ?


Code C - [expand]
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
char UART1_Initilize(long int baudrate) {
    int x = 0;
 
    x = ((F_OSC / ((long int)baudrate * 16)) - 1);
    
    if((x > 255) || (x < 0)) {
       x = ((F_OSC / ((long int)baudrate * 64)) - 1);
 
        if((x > 255) || (x < 0)) {
            return 1;       //UART initialization failed
        }
        else {
            BRGH_bit = 0;   //low baudrate
        }
    }
    else {
        BRGH_bit = 1;       //high baudrate
    }
    
    SPBRG = x;              //set SPBRG value
    
    if(x < 256) {
        SYNC_bit = 0;      //setting Asynchronous mode for UART
        SPEN_bit = 1;      //enable Serial Port
        CREN_bit = 1;      //enable Continuous Reception
        TXEN_bit = 1;      //enable Transmission
        TXIE_bit = 0;      //disable transmit interrupt
    }
    
    return 0;              //UART initialization successful
}

 

Is this code correct ?
Hopefully. You should test it.

Using long int function parameter baurate and type casting inside the function is doing things twice. It doesn't hurt, but I'm still not sure if you understood the basic problem.

I'm not sure how the built-in Mikro-C functions handles baud rate, but I guess if you set it to a constant value, all calculations are performed at compile time, reducing the actual code to loading the registers with constants, saving a lot of flash memory.
 

Yes, I understood what you were saying. You were saying that instead of casting the result of unsigned int baudrate multiplied with 16 and casting the whole result into unsigned long int, I have to cast either baudrate or value 16 into unsigned long and then do the multiplication.

Even I am not sure how mikroC PRO PIC's UART_Init() function works but I want to know whether my function in post #7 is correct or not. It has to work for all baudrates and F_OSC values.
 

Just make the '4000000' for the crystal frequency '4000000ul'. This will help force the compilers calculations to use long integer arithmetic.
Susan
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top