All Forums > Programming Questions

Strange behavior on ATmega 328

(1/2) > >>

Paul:
Hello,

I have a strange problem with a piece of code. I think it is a bug of some sort..
The hardware is a morse code keyer with a controller for an attenuator. The hardware which I use is very simple. An Atmel ATmega328P running at 8MHz on its internal oscillator. The keyer is connected to PD4. (It is a LED at the moment...) The serial port is going through a RS485 converter chip, with the TX enable (RX disable) connected to PD2.

The issue I am seeing is that the LED lights up very dimly if I use the code below. If I disconnect the LED I measure the full 5V voltage swing on the AVR pin, but for some reason the AVR is unable to deliver enough current.

The moment I move the statement on LINE 2 to the location of LINE 3, the LED starts lighting up properly...
If I move the LED from PD4 to PD3 the LED lights up properly with LINE 2 at the current position.

The only serial communication I see coming in, with the attenuator functions enabled, is the header which I send, and then after a period of time when the attenuator setting is changed to "20" the serial line becomes active again. This till the moment the attenuator is set at "40".
So this has clearly to do with bit PB2. The moment PB2 is HIGH, the serial port sends. So the only conclusion I can draw is that PB2 directly influences PD2.
This effect is there with LINE 2 at the current position and LINE 2 at the LINE 3 position.

The strange thing is if I remove all references to the attenuator, so basically remove LINE 1, 2 and 5, the keyer works fine with all serial comms. The only issue is then the dimly lit LED, unless I move it to PD3.

There is something going on with the PORTB and PORTD influencing each other in a strange way....

Can anyone tell me what I am doing wrong or what the issue might be? (And how to avoid it! :) )

See below for the code... (Sorry for the possibly lesser quality code...)

Thanks for all the help...

Paul

--- Quote ---
#include <TimedAction.h>

struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
     {'.', 106}, {',', 115}, {':', 71}, {'\'', 94}, {'-', 97}, {'(', 45},
        {')', 109}, {'"', 82} , {'@', 86}, {'=', 49} , {'?', 76}, {'/', 41},
    {'A', 6}  , {'B', 17} , {'C', 21}, {'D', 9}  , {'E', 2} , {'F', 20},
   {'G', 11} , {'H', 16} , {'I', 4} , {'J', 30} , {'K', 13}, {'L', 18},
   {'M', 7}  , {'N', 5}  , {'O', 15}, {'P', 22} , {'Q', 27}, {'R', 10},
   {'S', 8}  , {'T', 3}  , {'U', 12}, {'V', 24} , {'W', 14}, {'X', 25},
   {'Y', 29} , {'Z', 19} , {'1', 62}, {'2', 60} , {'3', 56}, {'4', 48},
   {'5', 32} , {'6', 33} , {'7', 35}, {'8', 39} , {'9', 47}, {'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

const int key1Pin = PD4;
const int att1Pin = PB5;
const int attPort = PORTB;
const int key1WPM = 12;

char key1Att;
char att1Set;
char* msg1 = "THE QUICK BROWN FOX JUMPES OVER THE LAZY DOG.";
int key1DotT = (int)(1200/key1WPM/5);

volatile char key1Busy;
volatile int key1Mark;
volatile int key1Space;
volatile char key1SpaceSent;
volatile char key1Pat;
volatile char* key1Msg;
volatile char key1MsgP;

TimedAction keyertimer = TimedAction (5, keyisr);

void setAttenuator (char att, char key) {
  att1Set = 20;
  if (att == 00) { portWrite(attPort, 146); return; }
  if (att == 10) { portWrite(attPort, 19); return; }
  if (att == 20) { portWrite(attPort, 134); return; }
  if (att == 30) { portWrite(attPort, 7); return; }
  if (att == 40) { portWrite(attPort, 152); return; }
  if (att == 50) { portWrite(attPort, 25); return; }
  if (att == 60) { portWrite(attPort, 140); return; }
  if (att == 70) { portWrite(attPort, 13); return; }
  portWrite(attPort, 146);
  return; 
}

void keyisr () {
  keyer1();
  setAtt();  // <-- LINE 1
}

void setAtt() {
  if (att1Set-- > 0) digitalWrite(att1Pin, HIGH); else digitalWrite(att1Pin, LOW);
}

void keyer1 () {
  unsigned char cnt;
  if (key1Busy == 1) {
    if (key1Mark > 0) { digitalWrite(key1Pin, HIGH); key1Mark--; return; }
    if (key1Space > 0) { digitalWrite(key1Pin, LOW); key1Space--; return; }
    if (key1Pat > 1) {
      if (key1Pat & 1) key1Mark = (3*key1DotT); else key1Mark = key1DotT;
      key1Space = (2*key1DotT);
      key1Pat = key1Pat / 2;
      return;
    }
    if (key1SpaceSent == 0) {
      key1Space = (3*key1DotT);
      key1SpaceSent = 1;
      return;
    }
    if (key1Msg[key1MsgP+1] != NULL) {
      key1MsgP++;
      if (key1Msg[key1MsgP] == ' ') {
        key1Space = (7*key1DotT);
        key1SpaceSent = 1;
        Serial.print(" ");
        return;
      }
      for (cnt=0; cnt<N_MORSE; cnt++) {
        if (morsetab[cnt].c == key1Msg[key1MsgP]) {
          key1Pat = morsetab[cnt].pat;
          Serial.print(key1Msg[key1MsgP]);
          key1SpaceSent = 0;
          return;
        }
      }
      key1Pat = 76;
    } else {
      key1MsgP = 0;
      key1Busy = 0;
    }
  }   
}

void setup() {
  portMode(attPort, OUTPUT); // <-- LINE 2
  pinMode(PD4, OUTPUT);
  pinMode(PD2, OUTPUT);
  pinMode(PC4, INPUT);
  pinMode(PC5, INPUT);
                              // <-- LINE 3
  digitalWrite(PD2, HIGH);    // <-- LINE 4

  Serial.begin(115200) ;
  Serial.println("Bug reproduction");
  Serial.println("================");
  delay(2500);
  key1Busy = 0;
  key1SpaceSent = 1;
  key1Att = 0;
  att1Set = 0;
  keyertimer.enable();
}

void loop() {
  keyertimer.check();
  if (key1Busy == 0) {
    Serial.println("");
    Serial.print("Attenuator setting: -");
    Serial.print(key1Att, DEC);
    Serial.println("dB");
    setAttenuator(key1Att, 1);    // <-- LINE 5
    key1Att = key1Att + 10;
    if (key1Att > 70) key1Att = 0;
    key1Msg = msg1;
    key1MsgP = -1;
    key1Busy = 1;
  }
}

--- End quote ---

bhagman:
I can see one glaring problem.

You're using constants such as "PD4" and "PB2" - but these will not work with any of the Wiring Framework functions.

Use these instead for the ATmega328P:

PD0 -> 0
PD1 -> 1
PD2 -> 2
PD3 -> 3
PD4 -> 4
PD5 -> 5
PD6 -> 6
PD7 -> 7

PB0 -> 8
PB1 -> 9
PB2 -> 10
PB3 -> 11
PB4 -> 12
PB5 -> 13

PC0 -> 14
PC1 -> 15
PC2 -> 16
PC3 -> 17
PC4 -> 18
PC5 -> 19

PORTD -> 0
PORTB -> 1
PORTC -> 2


So, for example:


--- Code: ---const int key1Pin = 4;   // i.e. pin 4
const int att1Pin = 13;  // i.e. pin 13 = PB5
const int attPort = 1;   // i.e. port 1 = PORTB
--- End code ---

Try that.

Paul:
Thanks for your reply.
But you write:

--- Quote ---You're using constants such as "PD4" and "PB2" - but these will not work with any of the Wiring Framework functions.
--- End quote ---
How come the program works absolutely fine if I make the changes as described in my 1st post?

Where can I find the pin numbers in the documentation? I searched and could not find it; Therefore I tried the constants and it worked...?

I will change the program today and try again. I will let you know the outcome.

Paul

Paul:
It is working now :)
What I have done is all the pin names and port names defined using "#define PD0 0" etc.
Will that influence the functioning of the framework in any way? Is it advisable to do this or not? Would it be an option to include with the framework header files for each processor, so the pin names and port names could be used? Or is there a good reason not to do this???

I am still confused about the previous behavior though; Especially the dimly lit LED...  ???

Thanks

Paul

bhagman:

--- Quote from: Paul on November 15, 2011, 07:20:06 PM ---What I have done is all the pin names and port names defined using "#define PD0 0" etc.

--- End quote ---

I wouldn't recommend this.

It sounds to me that you have worked on Atmel's controllers before and that you're become accustomed to using the definitions provided by the header files defined within the AVR-GCC port of the GCC compiler.

The thing to remember with the Wiring Framework is that it abstracts away the fiddly bits of the controllers, so that it makes it easier for people to program them.

You will want to start using the pin numbering scheme used in the Wiring Framework to keep things consistent.  Adding new #defines will just confuse you later ("why did I redefine PD0?").


The reason why some of the things worked before was that you were just getting lucky by the fact that PD0 = pin 0, PD1 = pin 1, etc... (in the #ioxxxx.h files, PD0 = 0, PD1 = 1, etc) So things attached to PORTD were working as you expected.

Now, about the dimly lit LED - if the pin that it was on was not defined as an OUTPUT, it will stays defined as an INPUT, and on the AVR microcontrollers, when you write to a PORT, it turns on a weak pull-up which is what illuminated your LED (using very little current).

Navigation

[0] Message Index

[#] Next page

Go to full version