|
|
View previous topic :: View next topic |
Author |
Message |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
ports with parameters |
Posted: Mon Feb 12, 2018 3:53 pm |
|
|
Hello everyone
I am trying to use the pins with a parameter. For example on 18f4550 pin_B2 is 31754. I am trying to add this value 1 and use the pin b3 which is 31755
i use this function and it works
Code: |
output_high(DIGITAL_PORT_BASE + 1); |
but
when i use this the code doesnt work. and compiler gives no warning or ect.
Code: | int rgb_port = 1;
output_high(DIGITAL_PORT_BASE + rgb_port);
|
i tried to change the type of rgb_port to long and int16 and byte but neither of them worked. Can you see what is the problem here.
Here is my full code. when i change the lines in neobit function.
output_high(DIGITAL_PORT_BASE+ rgb_port);
it does not work
however when i use
output_high(DIGITAL_PORT_BASE+ 1);
it works just fine
Code: |
#include <18F4550.h>
#DEVICE ADC=10
#fuses HSPLL,NOWDT,NOMCLR,PROTECT,NOLVP,NODEBUG,NOBROWNOUT,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#use rs232(baud=9600, UART1, ERRORS,stream = bt)
#define DIGITAL_PORT_BASE PIN_B2
#define LEDNUM 1 // 1 led var
void neobit(int);
void led_on();
void led_choose(int,int,int,int); // x tane ledden hangisini yakacagimizi seciyor ve o led icin R,G ve B renk degerini bekliyor
void get_color();
unsigned int8 red[LEDNUM] = {}; //kirmizi degerleri (1. ledin kirmizisi, 2. ledin kirmizisi seklinde ilerliyor)
unsigned int8 green[LEDNUM] = {}; //yesil degerleri
unsigned int8 blue[LEDNUM] = {}; // mavi degerleri
int rgb_port = 1;
//RGB ledlerdin her biri 24 bit komut bekliyor. ilk 8 bit yesilin parlaklığı, 2. 8 bit kirmizi ve 3. 8 bit mavi icin.
void main()
{
delay_ms(2000);
while(true)
get_color();
}
void neobit(int bit) // rgbdeki entegre '1' icin 0.9us high bekliyor. '0' icin ise 0.35us high bekliyor. Bu fonksiyon aldigi bite gore high ve low veriyor.
{
if(bit==1)
{
output_high(DIGITAL_PORT_BASE);
delay_cycles(6);
output_low(DIGITAL_PORT_BASE);
}
else
{
output_high(DIGITAL_PORT_BASE);
delay_cycles(3);
output_low(DIGITAL_PORT_BASE);
}
}
void led_on() // gelen renk degerinin bitlerine bakarak duruma gore '1' veya '0' gonderiyor. Girdigimiz integer degerini rgbye gonderiyoruz.
{
int i=0;
int a=0;
for(a=0;a<LEDNUM;a++)
{
for(i=8;i>0;i--)
{
neobit(bit_test(green[a],(i-1)));
}
for(i=8;i>0;i--)
{
neobit(bit_test(red[a],(i-1)));
}
for(i=8;i>0;i--)
{
neobit(bit_test(blue[a],(i-1)));
}
output_low(DIGITAL_PORT_BASE);
}
}
void get_color() // her bir led icin kullanicidan renk aliyor
{
int i=0;
for(i=0;i<LEDNUM;i++)
{
red[i]=10;
putc('r',bt);
green[i]=0;
putc('g',bt);
blue[i]=50;
putc('b',bt);
}
led_on();
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 12, 2018 5:36 pm |
|
|
It worked for me. I made the test program shown below. Then I ran
it in MPLAB vs. 8.92 simulator with a Watch window open, showing LATB.
The Watch window shows:
The value of 0x08 shows that Pin B3 is set. This is the correct result.
This was tested with with CCS vs. 5.076.
Code: |
#include <18F46K22.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT
#use delay(clock=4M)
#define DIGITAL_PORT_BASE PIN_B2
//======================================
void main(void)
{
int16 rgb_port = 1;
output_high(DIGITAL_PORT_BASE + rgb_port);
while(TRUE);
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Mon Feb 12, 2018 5:59 pm |
|
|
hopefully someone else will explain but I did a quick code test.
...stuff added to my program
#define test pin_b2
int8 offest=1;
...results from listing
Code: |
190: output_high(test);
06A2 9493 BCF 0xf93, 0x2, ACCESS
06A4 848A BSF 0xf8a, 0x2, ACCESS
191: output_high(test+1);
06A6 9693 BCF 0xf93, 0x3, ACCESS
06A8 868A BSF 0xf8a, 0x3, ACCESS
192: output_high(test+offest);
06AA 0E0A MOVLW 0xa
06AC 2439 ADDWF 0x39, W, ACCESS
06AE 6E3A MOVWF 0x3a, ACCESS
06B0 0E7C MOVLW 0x7c
06B2 6E3B MOVWF 0x3b, ACCESS
06B4 B0D8 BTFSC 0xfd8, 0, ACCESS
06B6 2A3B INCF 0x3b, F, ACCESS
06B8 C03A MOVFF 0x3a, 0x3c
06BC 0E01 MOVLW 0x1
06BE 6E3D MOVWF 0x3d, ACCESS
06C0 0E0F MOVLW 0xf
06C2 6E3F MOVWF 0x3f, ACCESS
06C4 0E89 MOVLW 0x89
06C6 6E3E MOVWF 0x3e, ACCESS
06C8 DF5F RCALL 0x588
06CA C03A MOVFF 0x3a, 0x3c
06CE 6A3D CLRF 0x3d, ACCESS
06D0 0E0F MOVLW 0xf
06D2 6E3F MOVWF 0x3f, ACCESS
06D4 0E92 MOVLW 0x92
06D6 6E3E MOVWF 0x3e, ACCESS
06D8 DF57 RCALL 0x588
AND
0588 503C MOVF 0x3c, W, ACCESS
058A 0B07 ANDLW 0x7
058C 6E00 MOVWF 0, ACCESS
058E 303C RRCF 0x3c, W, ACCESS
0590 6E01 MOVWF 0x1, ACCESS
0592 3201 RRCF 0x1, F, ACCESS
0594 3201 RRCF 0x1, F, ACCESS
0596 0E1F MOVLW 0x1f
0598 1601 ANDWF 0x1, F, ACCESS
059A 5001 MOVF 0x1, W, ACCESS
059C 243E ADDWF 0x3e, W, ACCESS
059E 6EE9 MOVWF 0xfe9, ACCESS
05A0 0E00 MOVLW 0
05A2 203F ADDWFC 0x3f, W, ACCESS
05A4 6EEA MOVWF 0xfea, ACCESS
05A6 6A01 CLRF 0x1, ACCESS
05A8 2A01 INCF 0x1, F, ACCESS
05AA 2A00 INCF 0, F, ACCESS
05AC D001 BRA 0x5b0
05AE 3601 RLCF 0x1, F, ACCESS
05B0 2E00 DECFSZ 0, F, ACCESS
05B2 D7FD BRA 0x5ae
05B4 523D MOVF 0x3d, F, ACCESS
05B6 E003 BZ 0x5be
05B8 5001 MOVF 0x1, W, ACCESS
05BA 12EF IORWF 0xfef, F, ACCESS
05BC D003 BRA 0x5c4
05BE 1E01 COMF 0x1, F, ACCESS
05C0 5001 MOVF 0x1, W, ACCESS
05C2 16EF ANDWF 0xfef, F, ACCESS
05C4 0C00 RETLW 0
|
As you can see in the code at 190 and 191 , the compiler creates very,very 'tight' or short code.
In 192 the compier creats 20+ lines AND there are 2 'calls' so a routine at 0x0588, which itself is some 20 + instructions.
All told the 3rd version is at least 60 times bigger and therefore 60 times slower in execution !
As stated in the other reply, this is why it doesn't run. Actually it does run,just won't work as expected. Your neopxl is 'time sensitive', same as the 1 wire devices. Just copy the 'driver',recode for more pins.
Jay
Last edited by temtronic on Tue Feb 13, 2018 6:41 am; edited 2 times in total |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Tue Feb 13, 2018 12:42 am |
|
|
i am sorry, i forgot to explain how iy doesnt work. i cannot see a color on rgb. if i use output_high(digital_port_base + 1) i see the color. the rgb led is ws2812 5050.
pcm programmer, i wrote a new function and did what you did. it worked for me too. i cannot make the neobit function work. it seems the problem is in there. however, using 1 instead of rgb_port makes it work too. i could not find the mistake. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Feb 13, 2018 1:33 am |
|
|
OK.
Key is to understand what is involved.
If you code a 'fixed' pin (so input(PIN_A1) for example), the maths is all done at compile time. The code that results is just the actual machine instructions to access this pin. Hence small/fast code.
Using a variable for a pin, brings a big cost. At run time, the code has to work out the port address and the bit masks needed to access the pin. Typically perhaps a dozen instructions. Now this won't work with anything involving tight timings. This has been covered here before for the Dallas 'one wire' bus.
If you search for multiple 18B20, you should find threads about this. The reliable solution, is to just have duplicate code I'm afraid....
So the code is actually 'working', but the overhead involved makes it not function for the timings needed. This is unfortunately inherent with the chip, not something that can be fixed by ingenious code.
It is possible to solve for multiple bits on the same port, by doing the maths yourself, in advance of the timing operations. Whether this might work for your would depend on how many pins you actually want to use, and where they are on the chip?. Generally if the number of pins involved is small, it is actually easier to just use the duplicate code solution. |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Tue Feb 13, 2018 2:05 am |
|
|
Ttelmah wrote: | OK.
Key is to understand what is involved.
If you code a 'fixed' pin (so input(PIN_A1) for example), the maths is all done at compile time. The code that results is just the actual machine instructions to access this pin. Hence small/fast code.
Using a variable for a pin, brings a big cost. At run time, the code has to work out the port address and the bit masks needed to access the pin. Typically perhaps a dozen instructions. Now this won't work with anything involving tight timings. This has been covered here before for the Dallas 'one wire' bus.
If you search for multiple 18B20, you should find threads about this. The reliable solution, is to just have duplicate code I'm afraid....
So the code is actually 'working', but the overhead involved makes it not function for the timings needed. This is unfortunately inherent with the chip, not something that can be fixed by ingenious code.
It is possible to solve for multiple bits on the same port, by doing the maths yourself, in advance of the timing operations. Whether this might work for your would depend on how many pins you actually want to use, and where they are on the chip?. Generally if the number of pins involved is small, it is actually easier to just use the duplicate code solution. |
thank you for your answer Ttelmah. i will try what you said.
i want to use one pin. the project requires it.
i thought that the problem might be about speed actually. i tried to make the adding rgb port on a different place.
the code was like this
int16 port= digital_port_base + rgb_port;
output_high(port);
it did not work. i thought the adding process takes too long so if i do it 1 time it would solve my problem. you said the problem is the integer being there which explains why this code did not work too. i will try to write a switch case function. if rgb port is 0 digitalportbase is 31754 if 2, 31755. hope it works. thank you so much! |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Tue Feb 13, 2018 2:40 am |
|
|
as you said ttelmah, this ugly piece of code worked for me
Code: | void neobit(int bit,int port) // rgbdeki entegre '1' icin 0.9us high bekliyor. '0' icin ise 0.35us high bekliyor. Bu fonksiyon aldigi bite gore high ve low veriyor.
{
switch(port){
case 0:
if(bit==1)
{
output_high(31754);
delay_cycles(6);
output_low(31754);
}
else
{
output_high(31754);
delay_cycles(3);
output_low(31754);
}
break;
case 1:
if(bit==1)
{
output_high(31755);
delay_cycles(6);
output_low(31755);
}
else
{
output_high(31755);
delay_cycles(3);
output_low(31755);
}
break;
case 2:
if(bit==1)
{
output_high(31756);
delay_cycles(6);
output_low(31756);
}
else
{
output_high(31756);
delay_cycles(3);
output_low(31756);
}
break;
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Feb 13, 2018 5:07 am |
|
|
As a comment though, if you are only actually using one pin, then just use a #define, rather than a variable.
Code: |
#define NEOPIN PIN_xx //set this to the pin you want
void neobit() // rgbdeki entegre '1' icin 0.9us high bekliyor. '0' icin ise 0.35us high bekliyor. Bu fonksiyon aldigi bite gore high ve low veriyor.
{
output_high(NEOPIN);
delay_cycles(6);
output_low(NEOPIN);
}
|
You can then compile for any pin you want, by just changing the define. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Thu Feb 15, 2018 1:21 pm |
|
|
As an additional idea, if you do end up using multiple pins (as your example code shows), then you can use a macro to tidy up the code some:
Code: |
#define neobit_impl(bit,pin) \
if (bit == 1){ \
output_high(pin); \
delay_cycles(6); \
output_low(pin); \
}else{ \
output_high(pin); \
delay_cycles(3); \
output_low(pin); \
}
void neobit(int bit,int port)
{
switch(port){
default:
case 0: neobit_impl(bit,31754); break;
case 1: neobit_impl(bit,31755); break;
case 2: neobit_impl(bit,31756); break;
}
}
|
It will generate identical code to your example (well I added the "default" case in the switch statement, but otherwise identical), so it will still take up the same code space and will run just as fast, but it might be easier for you to read. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 15, 2018 1:30 pm |
|
|
Also, the o.p. is using magic numbers which actually come from the .h
file of the PIC:
Code: |
#define PIN_B2 31754
#define PIN_B3 31755
#define PIN_B4 31756
|
There is little reason to use magic numbers, so an improvement would be:
Code: |
switch(port){
default:
case 0: neobit_impl(bit, PIN_B2); break;
case 1: neobit_impl(bit, PIN_B3); break;
case 2: neobit_impl(bit, PIN_B4); break;
|
|
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Fri Feb 16, 2018 1:51 am |
|
|
Thank you for yor answers.
jeremiah, on your code
Code: | #define neobit_impl(bit,pin) |
is pin an integer? using an integer on the neobit function slows my code and rgb doesnt show a color. if its not, can you tell me what it is? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Feb 16, 2018 3:10 am |
|
|
As a general solution, let me post a relatively efficient way of doing multiple pins:
Code: |
#define SELECTED_HIGH() *Physical_port |= mask
#define SELECTED_LOW() *Physical_port &= not_mask
unsigned int16 Physical_port;
unsigned int8 mask, not_mask;
void select(unsigned int16 pin)
{
Physical_port=pin/8;
mask=0;
bit_set(mask, pin & 7);
not_mask=mask^0xFF;
}
#inline
void neobit(void) //Pulse the currently selected pin
{
SELECTED_HIGH(); //set selected pin high
delay_cycles(6);
SELECTED_LOW(); //set selected pin low
}
//Then call this like:
select(PIN_A1); //whatever pin you are currently using
neobit(); //pulse the selected pin
|
What you do is 'select' the pin you want, and then the OR and the & function like the output high and output low.
One 'caveat', the pin has to have been switched to drive in advance (this doesn't change the TRIS), but assuming the setup code will already have used an output_high or an output low to preset the pin, it'll already have the TRIS set correctly. This is almost as fast as the 'non variable' version. This is what I was referring to earlier when I talked about 'doing the maths in advance'. The 'select' function, does the maths to generate the bit masks and the physical port address.
So you can have the complete function set required to do whatever operation(s) you require, and just 'select' the pin(s) required, and call these. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Fri Feb 16, 2018 5:09 am |
|
|
doguhanpala wrote: |
jeremiah, on your code
Code: | #define neobit_impl(bit,pin) |
is pin an integer? using an integer on the neobit function slows my code and rgb doesnt show a color. if its not, can you tell me what it is? |
#define is a text substitution, it doesn't "know" about types, it simply replaces "pin" with the text you give it. It is not a function in the C sense at all; there is no call and return; only text replacement. It therefore produces inline code. Pin is not a "number" at all, merely text.
Pin constants are unsigned int16s. Int is unsigned 8 bit on 12/16/18 PICs, and signed int16 on 24/dsPic/33s. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Fri Feb 16, 2018 9:23 am |
|
|
doguhanpala wrote: | Thank you for yor answers.
jeremiah, on your code
Code: | #define neobit_impl(bit,pin) |
is pin an integer? using an integer on the neobit function slows my code and rgb doesnt show a color. if its not, can you tell me what it is? |
As RF_Developer said, it isn't a function so there is no type. The type of "pin" is whatever you put there. If you put a constant number, it will be a constant number. If you put an integer variable, it will be an integer variable. The code I posted will expand to *exactly* the same code you posted. It is text substitution (as RF_Developer mentioned to you)
I would highly recommend you reading up on how C macros work. They can be very powerful (and also dangerous). |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|