Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

C port question

Status
Not open for further replies.

AtomSoft

Well-Known Member
Hey guys this might be a silly question but i want to make a function like:

Code:
blinkme (port){
port = 0x00;
delay;
port = oxff;
delay
}

the only question i have is how do i send port? Like will i need to use a pointer?

so it would be something like:

Code:
blinkme (unsigned char *port){
port = 0x00;
delay;
port = oxff;
delay
}

and i call it like blinkme(portb);

????????

i might not even use this but just wanted to know :D i am curious
 
Last edited:
COOL! ok thanks!!!

Hey guys i have some cool LCD code coming out by tomorrow. Will give you some options like

LCD PORT
CUSTOM (RS/RW/E) Lines
ENDIAN aka Nibble (UPPER/LOWER)
RW or GND'ed RW MODE

Here is a sample :

Code:
#define ENDIAN   0          //0 = 0:3 *** 1 = 4:7

#define LCD_PORT LATB               //LCD DATA PORT
#define LCD_TRIS TRISB              //LCD DATA DIRECTION PORT
#define LCD_DATA PORTB              //LCD INPUT DATA VALUES
#define LCD_RW   LATBbits.LATB4     //LCD Read/Write Control
#define LCD_RS   LATBbits.LATB5     //LCD Command/Data Control
#define LCD_E    LATBbits.LATB6     //LCD Enable Line

Using the above will use RB0 to RB3 for data lines of LCD

ENDIAN = 1 would use RB4 to RB7
Comment out RW and it will assume RW is grounded and use delays instead of busy check.
 
It won't work that way, you are passing it the value on portb. You need to pass the address and so need to do blinkme(&portb) or blinkme(PORTB).

Mike.
 
Just be aware that that still requires the compiler to be smart enough to handle bank switching etc, PORTB is not just an address in linear space, it's in a 2D space where the bank must also be correct as well as the address.

I don't know about C18 but with the MikroC compiler it generally tries to leave the banks default switched to 00 so it would probably work most of the time.

But it's not really a pure C issue, you are dealing with device specific register bank switching and using the compiler's ability to indirectly address using a pointer is going to be risky, and even more so if the came C code is used on different devices that the compiler might handle differently...

I would probably do it in a more "bulletproof" fashion;
blinkme (the_port){
if(the_port=='A') PORTA = 0x00;
if(the_port=='B') PORTB = 0x00; // etc
}

That is guaranteed to always produce the desired result, on any PIC, ported to any compiler, even ported to other languages. And in terms of code size and execution speed I don't think there will be much difference between using a pointer and getting the compiler to handle indirect addressing.
 
I don't know about MikroC as I've never used it but with BoostC ram pointers are 16 bits and so there is no need to worry about banking. You could do blinkme(0x1c0) and it will modify location 0x40 in bank 3. In C18 there are two types of ram pointers, near (8 bit) and far (16 bit), the SFRs are all accessible with a near pointer.

I would be surprised if any C compiler didn't handle the banking with ram pointers.

Mike.
 
yeah i know heh i figured id just use definitions ... here is some LCD Code im making now. What cha think so far? Its not done by a long shot but so far i like it heh

1 question... how does one test a definitions value? like

#IFDEF SOMETHING = 2
if something is 2 then use this code when compiling.
#ENDIF

Here is my LCD.H:
Code:
#ifndef __LCD_H
#define __LCD_H

#include <delays.h>
#include <p18cxxx.h>

#define ENDIAN   0          //0 = 0:3 *** 1 = 4:7

#define LCD_PORT LATB               //LCD DATA PORT
#define LCD_TRIS TRISB              //LCD DATA DIRECTION PORT
#define LCD_DAT PORTB              //LCD INPUT DATA VALUES
#define LCD_RW   LATBbits.LATB4     //LCD Read/Write Control
#define LCD_RS   LATBbits.LATB5     //LCD Command/Data Control
#define LCD_E    LATBbits.LATB6     //LCD Enable Line

#define CMD 0
#define TXT 1

#define LOWER 0
#define UPPER 1

#define LOWEND 0x08
#define UPPEND 0x80

#define LOWMSK 0x0F
#define UPPMSK 0xF0

#define MHz *1000000
#define MYFOSC 8MHz

void WaitLCDBusy(void);
void LCD_Init(void);
void LCD_DATA(unsigned char data,unsigned char type);
void LCD_NYB(unsigned char nyb);
void DelayUs(unsigned long time);

extern unsigned char BF;
#endif

My LCD.C:
Code:
#include "lcd.h"
unsigned char BF;
void LCD_Init(void){
    if(ENDIAN == LOWER)
        BF = LOWEND;
    else
        BF = UPPEND;        
}
void LCD_DATA(unsigned char data,unsigned char type){
    #ifdef LCD_RW               //IF THE LCD_RW DEFINITION IS USED
        WaitLCDBusy();          //TEST LCD FOR BUSY 
    #endif                      //IF NOT SMALL DELAY AFTER

    if(type == CMD){
        LCD_RS = 0;                 //COMMAND MODE
    } else {
        LCD_RS = 1;                 //CHARACTER/DATA MODE
    }

    LCD_NYB(data>>4);            //WRITE THE UPPER NIBBLE
    LCD_NYB(data);               //WRITE THE LOWER NIBBLE

    #ifndef LCD_RW
        if(type == CMD){          //IF TYPE = COMMAND
            DelayUs(2000);        //DELAY 2 MilliSeconds
        } else {                  //IF TYPE = DATA
            DelayUs(50);          //DELAY 50 MicroSeconds
        }
    #endif
}
#ifdef LCD_RW
void WaitLCDBusy(void){
    LCD_RS=0;                       //COMMAND MODE
    LCD_RW=1;                       //READ MODE

    if(ENDIAN == LOWER){                //ENDIAN = 0? 
        LCD_TRIS |= LOWMSK;           //YES = SET LOWER NIBBLE INPUT
    } else {                        //ELSE ENDIAN = 1
        LCD_TRIS |= UPPMSK;           //SET UPPER NIBBLE INPUT
    }

    LCD_E=1;                        //ENABLE LCD DATA LINES
    while(LCD_DAT & BF);           //TEST BUSY FLAG BIT
    LCD_E=0;                        //DISABLE LCD DATA LINES

    if(ENDIAN == LOWER){                //ENDIAN = 0? 
        LCD_TRIS &= UPPMSK;           //YES = SET LOWER NIBBLE OUTPUT
    } else {                        //ELSE ENDIAN = 1
        LCD_TRIS &= LOWMSK;           //SET UPPER NIBBLE OUTPUT
    }

    LCD_RW=0;
}
#endif
void LCD_NYB(unsigned char nyb){
    if(ENDIAN == LOWER){                //ENDIAN = 0? Yes Send the data LOWER
        LCD_PORT &= UPPMSK;           //CLEAR LOWER PORT NIBBLE
        LCD_PORT |= (nyb & LOWMSK);   //SEND DATA LINE THE INFO 
    } else {                        //ENDIAN = 1 so send to HIGHER
        LCD_PORT &= LOWMSK;           //CLEAR UPPER PORT NIBBLE
        LCD_PORT |= ((nyb << 4) & UPPMSK);    //SHIFT DATA OVER << 4, CLEAR LOWER NIBBLE
    }
    LCD_E = 1;          //ENABLE LCD DATA LINE
    LCD_E = 0;          //DISABLE LCD DATA LINE
}

void DelayUs(unsigned long time){
    unsigned long timetemp;
    unsigned long x;

    timetemp = (( 1 / MYFOSC) * time);
    for(x=0;x<timetemp;x++){
        Nop();
    }
}
 
DAG!
Code:
#if ENDIAN = LOWER
    BF = LOWEND;
#else
    BF = UPPEND;        
#endif
[B][COLOR="Red"]
.....produces...
D:\Micro\PIC\LCD_LIB\lcd.c:6:Error [1029] malformed expression in '#if'[/COLOR][/B]

So i guess i cant :(

So ill stick with:
Code:
    if(ENDIAN == LOWER)
        BF = LOWEND;
    else
        BF = UPPEND;

Small hassle with warnings but heh... is there a way to remove the warning i get using the normal if? Which is:

D:\Micro\PIC\LCD_LIB\lcd.c:8:Warning [2056] expression is always true
D:\Micro\PIC\LCD_LIB\lcd.c:40:Warning [2056] expression is always true
D:\Micro\PIC\LCD_LIB\lcd.c:50:Warning [2056] expression is always true
D:\Micro\PIC\LCD_LIB\lcd.c:62:Warning [2056] expression is always true
 
I don't know about MikroC as I've never used it but with BoostC ram pointers are 16 bits and so there is no need to worry about banking. You could do blinkme(0x1c0) and it will modify location 0x40 in bank 3. In C18 there are two types of ram pointers, near (8 bit) and far (16 bit), the SFRs are all accessible with a near pointer.

I would be surprised if any C compiler didn't handle the banking with ram pointers.
...

Interesting, thanks for that info. I've got into a bad habit (good habit?) lately of always checking the compiler's generated ASM output and my C code for PIC (especially for 16F) has de-volved into some of the simplest C expressions that I know will compile down to the smallest and fastest ASM.

After seeing what a mess the compiler makes of some expressions and indirect addressing operations... And then a slight change to the C syntax and bingo it's 20 ASM instructions smaller/faster.

I've got to update to MikroC PRO, the old MikroC v7 i'm using was never great at some of the more subtle optimisations for PIC 16F assembler instructions.
 
No debuging with the pickit2 you have to buy there programmer.PICFlash with mikroICD support

But you can simulate and debug that way with just the ide.
 
Last edited:
It has real good simulation. You can run your code and debug in simulation.
 
Yes it makes a hex you can load with the pickit2 or jdm.
I like it It's the only C compiler I have really used. The biggest thing I like is that it is easy to setup and you can use it with all the chips i use 12f683 16f628 16f684 16f877 and the 18fxxx chips too
 
Gag me with a spoon

It has real good simulation. You can run your code and debug in simulation.

I have a thing about compiler vendors that require you to buy their debugger. It is a stupid money grubbing thing to do. Sure you can use a simulator but why should you have to when you can get a decent ICD like the PICkit2 for $40 ?

Less for more. Great Idea.

3v0
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top