 |
 |
| View previous topic :: View next topic |
| Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 20061
|
|
Posted: Sun Mar 06, 2016 11:13 am |
|
|
Comments inline:
| Code: |
#use rs232(uart2, baud=9600, stream=STD)
#use rs232(UART1, BAUD=250000,BITS=9,PARITY=N,STOP=1,ERRORS,stream=DMX, LONG_DATA)
//You are ignoring what you were told. The UART cannot generate 2 stops
//by selecting 2 stops you are forcing a software UART to be used...
int16 break_time;
int8 dmx_in[128]; //You are only using 8bit data
char dmx_index=0;
//You don't show a declaration for int_count
int16 int_count=500;
void main(void)
{
set_tris_d(0b01111111);
setup_timer_2(T2_DIV_BY_4,249,10);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_RDA); //Again answered at the start of the
//thread. UART1 gives INT_RDA. UART2 INT_RDA2
enable_interrupts(GLOBAL);
while(TRUE)
{
fprintf(STD, "value: %d\r\n", dmx_in[0]);
fprintf(STD, "value: %d\r\n", dmx_in[1]);
fprintf(STD, "value: %d\r\n", dmx_in[2]);
fprintf(STD, "value: %d\r\n", dmx_in[3]);
delay_ms(1000);
}
}
#INT_RDA
void dmx() {
// Is this a receiver interrupt on the DMX stream? It does not trigger...
//Because you are not using the UART.....
output_toggle(PIN_E1);
dmx_in[dmx_index++] = (int8)fgetc(DMX);
//Just store the low 8bits of the value
if (index==128)
index=127; //ensure this cannot overflow.
}
#INT_TIMER2
void timer2_isr()
{
// Timer interrupt every 1 mSec
if(--int_count==0) { // this program.
output_toggle(PIN_C1);
int_count = 500;
}
break_time++;
if (break_time > 15)
dmx_index = 0;
}
|
|
|
 |
JackB
Joined: 04 Mar 2016 Posts: 32 Location: Netherlands
|
|
Posted: Sun Mar 06, 2016 12:28 pm |
|
|
Hi Ttelmah,
Thank you very much for helping!
The once missing declaration was sitting in main.h, I moved it for clarity now.
One I enable INT_RDA, the timer interrupt gets slow and does no longer trigger per ms.
but about every 2 ms. Also when I disconnect the DMX signal.
My output is not printed to the serial port to the PC as well if that interrupt is enabled.
In my code I use multiple files for different parts, they all work fine, like adc, pwm, lm75, etc.
I get a compiler error:
A numeric expression must appear here
For this line within INT_RDA:
| Code: | | dmx_in[dmx_index++] = (int8)fgetc(DMX); |
If I comment this out, the code compiles.
I will now list the entire main.c and project.h, so maybe somebody can see what is wrong.
Both with the complier error as well as with slowing down and no longer printing output once this line is uncommented:
| Code: | | enable_interrupts(INT_RDA); // UART1 gives INT_RDA |
If the above line is commented out the rest of the code works fine.
project.h
| Code: |
#ifndef PROJECT_H
#define PROJECT_H
#include <18F67K90.h>
#fuses MCLR,HSH,NOPLLEN
#device ADC=12
#use delay(crystal=20mhz)
#use rs232(UART1, BAUD=250000,BITS=9,PARITY=N,STOP=1,ERRORS,stream=DMX, LONG_DATA)
#use rs232(uart2, baud=9600, stream=STD)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
enum errors { err_range, err_too_far, err_too_many };
#endif /* PROJECT_H */
|
main.c
| Code: |
#include "project.h"
#include "main.h"
#include "leds.h"
#include "switches.h"
#include "lm75.h"
#include "mcp7940n.h"
#include "pwm.h"
#include "adc.h"
#include "eeprom.h"
#include "dmx_receive.h"
int16 int_count;
int8 dmx_in[128];
char dmx_index;
int16 dmx_value;
int16 break_time;
int16 msecs;
void main()
{
fprintf(STD, "\r\nHello LED driver!\r\n");
dmx_index = 0;
msecs = 0;
// delay_cycles(4);
init_switches();
init_leds();
int_count = 500;
setup_timer_2(T2_DIV_BY_4, 249, 10);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_RDA); // UART1 gives INT_RDA
// enable_interrupts(INT_RDA2); // UART2 gives INT_RDA2
enable_interrupts(GLOBAL);
init_pwm(); // 1.25kHz
set_pwm1(50); // 20%
set_pwm2(100); // 40%
set_pwm3(150); // 60%
set_pwm4(200); // 80%
set_pwm5(250); // 100%
init_adc();
unsigned long count = eeprom_read_16(0);
while(1)
{
restart_wdt();
float temperature = read_lm75(7);
float ol1 = read_overload1_amps();
float ol2 = read_overload2_amps();
float ol3 = read_overload3_amps();
float ol4 = read_overload4_amps();
float ol5 = read_overload5_amps();
if (temperature > 70)
{
set_leds(6, 1);
} else {
set_leds(6, 0);
if (ol1 > 10) set_leds(1, 1);
if (ol2 > 10) set_leds(2, 1);
if (ol3 > 10) set_leds(3, 1);
if (ol4 > 10) set_leds(4, 1);
if (ol5 > 10) set_leds(5, 1);
}
if (msecs == 1000)
{
msecs = 0;
fprintf(STD, "current: %4.1fA, %4.1fA, %4.1fA, %4.1fA, %4.1fA", ol1, ol2, ol3, ol4, ol5);
fprintf(STD, ", value: %d %d %d %d %d", dmx_in[0], dmx_in[1], dmx_in[2], dmx_in[3], dmx_in[4]);
float pwm1 = get_pwm1_float();
float pwm2 = get_pwm2_float();
float pwm3 = get_pwm3_float();
float pwm4 = get_pwm4_float();
float pwm5 = get_pwm5_float();
fprintf(STD, ", pwm: %3.0f, %3.0f, %3.0f, %3.0f, %3.0f", pwm1, pwm2, pwm3, pwm4, pwm5);
fprintf(STD, ", temp: %3.1f °C ", temperature);
int options = read_option_switches();
long int dmx = read_dmx_switches();
char options[6];
fprintf(STD, ", options: %d, dmx: %ld", options, dmx);
fprintf(STD, ", count: %06ld", count++);
fprintf(STD, "\r\n");
eeprom_write_16(0, count);
}
}
}
#INT_RDA
void dmx() {
// Is this receiver interrupt on the DMX stream? Does not trigger?
// dmx_in[dmx_index++] = (int8)fgetc(DMX);
// if (dmx_index==128)
// dmx_index=127; //ensure this cannot overflow.
output_toggle(PIN_D7);
}
#INT_TIMER2
void timer2_isr()
{
// Timer interrupt every 1 mSec
if(--int_count==0) { // this program.
output_toggle(PIN_C1);
int_count = 500;
}
break_time++;
msecs++;
if (break_time > 15)
dmx_index = 0;
}
|
|
|
 |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 06, 2016 1:36 pm |
|
|
| Quote: | I get a compiler error:
A numeric expression must appear here
For this line within INT_RDA:
Code:
dmx_in[dmx_index++] = (int8)fgetc(DMX);
|
That's because you named the isr with the same name as the stream.
Apparently the compiler doesn't like that.
| Quote: |
#use rs232(UART1, BAUD=250000,BITS=9,PARITY=N,STOP=1,ERRORS,stream=DMX, LONG_DATA)
#INT_RDA
void dmx() {
// Is this receiver interrupt on the DMX stream? Does not trigger?
// dmx_in[dmx_index++] = (int8)fgetc(DMX);
// if (dmx_index==128)
// dmx_index=127; //ensure this cannot overflow.
output_toggle(PIN_D7);
} |
Rename it to dmx_isr() or something like that. I always do this.
Alternatively, using #case also fixes the problem.
| Code: | #include <18F67K90.h>
#case |
But renaming the routine as dmx_isr() is the best way.
| Quote: | Both with the complier error as well as with slowing down and no longer printing output once this line is uncommented:
Code:
enable_interrupts(INT_RDA); // UART1 gives INT_RDA |
If you comment out the fgetc() line in the isr, the program will fail.
You must read (get) the character in the isr. |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20061
|
|
Posted: Sun Mar 06, 2016 1:47 pm |
|
|
But also do keep the test on index size for the array, which you show removed.
Problem is that if (shouldn't happen, but 'if' often does), data keeps arriving without the break, you will start writing beyond the end of the array. A sure way of making the code go haywire. |
|
 |
JackB
Joined: 04 Mar 2016 Posts: 32 Location: Netherlands
|
|
Posted: Sun Mar 06, 2016 2:18 pm |
|
|
Hi thank you both!
Renaming to dmx_isr makes sense and that worked!
I also include the code to avoid crossing the buffer boundary.
But I had to comment it out because of the compiler error, which got solved now.
I need indeed to read the value in the isr to clear the interrupt. (I guess)
Temporary (compiler error) not doing that made the controller behave odd. (slow)
The heartbeat LED now blinks at 1Hz rate, which is good!
Printed code stops after a few seconds, and then goes on.
The data read from the dmx signal is is read as 0 0 0 0 0 or 0 0 0 78 0, where 78 is correct!
We are getting close, I guess! |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20061
|
|
Posted: Sun Mar 06, 2016 3:03 pm |
|
|
There is one critical thing missing.
In the Microchip code, dmx_break_time is set to zero whenever a byte is received. This way it'll only get to 15, when there is a gap in the characters. Your CCS code does not do this. |
|
 |
JackB
Joined: 04 Mar 2016 Posts: 32 Location: Netherlands
|
|
Posted: Mon Mar 07, 2016 8:04 am |
|
|
Thank you all! It is working very well!
How it was done in the end...
At Ttelmah, thank you very much for checking with me.
The break_time should only get to 15 during the break in the dmx signal.
Then the index is set to 0.
This is a way to know we are starting over the same sequence of received bytes.
First a value for dmx address 0, then for 1, and so up.
But do I need to clear framing errors and overrrun errors? (like I do with XC8)
How do I check for framing errors and clear them?
In some include file:
| Code: |
#use rs232(UART1, BAUD=250000,BITS=9,PARITY=N,STOP=1,ERRORS,stream=DMX, LONG_DATA)
|
(Part of) main.c
| Code: |
int16 int_count;
int8 dmx_in[128];
char dmx_index;
int16 dmx_value;
int16 dmx_break_time;
int16 msecs;
int8 dmx_signal_detected;
void main()
{
setup_timer_2(T2_DIV_BY_4, 249, 10);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_RDA); // UART1 gives INT_RDA
// enable_interrupts(INT_RDA2); // UART2 gives INT_RDA2
enable_interrupts(GLOBAL);
msecs = 0;
dmx_break_time = 0;
dmx_signal_detected = 0;
while(1)
{
set_pwm1(dmx_in[0+dmx_address]);
set_pwm2(dmx_in[1+dmx_address]);
set_pwm3(dmx_in[2+dmx_address]);
set_pwm4(dmx_in[3+dmx_address]);
set_pwm5(dmx_in[4+dmx_address]);
if (msecs >= 1000)
{
// Do this every second
msecs = 0;
restart_wdt();
dmx_address = read_dmx_switches();
}
}
}
#INT_RDA
void dmx_isr() {
// Is this receiver interrupt on the DMX stream? Does not trigger?
dmx_in[dmx_index++] = (int8)fgetc(DMX);
if (dmx_index==128)
dmx_index=127; // Ensure this cannot overflow.
if (dmx_break_time > 15) { // MARK time after Slot > 15mS, reset index
dmx_index = 0;
dmx_signal_detected = 1; // Flag indicates presence of DMX signal
}
dmx_break_time = 0; // Character received: reset break time
}
#INT_TIMER2
void timer2_isr()
{
// Timer interrupt every 1 mSec
if(--int_count==0) { // this program.
output_toggle(PIN_C1); // Heartbeat LED
int_count = 500;
}
if (dmx_break_time < 1000)
dmx_break_time++; // Increase measured break time by 1 mSec
if (dmx_break_time > 100)
dmx_signal_detected = 0; // Flag indicates presence of DMX signal
msecs++;
}
|
Last edited by JackB on Mon Mar 07, 2016 1:24 pm; edited 16 times in total |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20061
|
|
Posted: Mon Mar 07, 2016 8:16 am |
|
|
Good.
Mark the thread as 'solved' (only you can do this), then somebody else wanting stuff about DMX in the future can know there is a solution.
Best Wishes |
|
 |
JackB
Joined: 04 Mar 2016 Posts: 32 Location: Netherlands
|
|
Posted: Mon Mar 07, 2016 8:47 am |
|
|
The only open question is this:
Do I need to clear framing errors and overrrun errors? (like I do with XC8)
How do I check for framing errors and clear them? |
|
 |
Ttelmah
Joined: 11 Mar 2010 Posts: 20061
|
|
Posted: Mon Mar 07, 2016 9:06 am |
|
|
| If you have 'ERRORS' in the #USE RS232 (you do), the compiler clears these automatically when the UART is read (actually copies them into a variable called 'RS232_ERRORS', so you can test them if needed). Without 'ERRORS', you have to clear them yourself. |
|
 |
temtronic
Joined: 01 Jul 2010 Posts: 9632 Location: Greensville,Ontario
|
|
Posted: Mon Mar 07, 2016 9:49 am |
|
|
I've been following this 'thread' and I think we've another convert !!
It looks like nice, clean, easy to read code.
Well done.
Jay |
|
 |
JackB
Joined: 04 Mar 2016 Posts: 32 Location: Netherlands
|
|
Posted: Mon Mar 07, 2016 10:45 am |
|
|
Thank you all for your great support!
I'm new to this and learning a lot from you, guys!
How do I mark the thread as 'solved' ? |
|
 |
temtronic
Joined: 01 Jul 2010 Posts: 9632 Location: Greensville,Ontario
|
|
Posted: Mon Mar 07, 2016 12:31 pm |
|
|
easy.. just open the thread up, goto first post, click 'edit' then add [solved] in the subject line.
Jay |
|
 |
|
|
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
|