My issue arises with the variable total. The debugger steps over like it's not even there, or if you get rid of the *, it runs and runs and provides a weird number. The idea of the program is to add dimes (or 10) to the total until it is greater than the goal which is 10000.
I'm writing this in C with IAR Embedded Workbench and am using a MSP430G2553.
#include <msp430g2553.h>
#include <stdio.h>
volatile unsigned int i;
int dime=0;
int goalz =10000;
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= 0x00;
for(;;){
P1OUT =0x01;
while(1)
{
if((BIT4 & P1IN))
{
P1OUT |= 0x01;
dime++;
int *total = 0;
*total = &dime;
}
else
{
P1OUT |= 0x00;
}
}
}
}
int *total = 0;
*total = &dime;
that is wrong, because you're trying to store the address of dime (not its value) in the location pointed by total, i.e. zero => not what you want (someone suggests this is the location of a register, so even if it doesn't crash, it's not valid. Writing the INTENA register is not good!).
The debugger probably optimizes out this statement, writing directly in zero.
not completely sure of what you want to achieve, but you have to declare total as a global variable and add dime to it. No need to use pointers or variable addresses here.
Probably, the debugger is steps over since the compiler is not even generating the code. You are creating the variable total (pointer or integer) in the stack (i.e., you add an item), you assign a value, and then you are out of scope so the variable is not there anymore.
I think that what you are trying to achieve is:
if (...) {
static int total = 0;
total = dime
}
but, then again, the variable total is completely useless, since it will always be the same value as dime. How should be total and dime different?
Related
I made a function, where PWM signal is generated at the output (PORTD) without usage of PWM control registers inside PIC microcontroller (PIC18F452). In order to slowly dim LED connected at the output, I was trying to increase the time needed for pulse to advance from 0% of one period to 100% of one period of square wave, while having square wave frequency constant. Everything should go as planned, except that second parameter being passed into pwm function, somehow resets, when going from 655 to 666 (that is, when duty cycle is at 65%). After this event, value being passed to pwm function proceeds from 0. Where as it should not reset at transition from 655 to 656 but at transition from 1000 to 1001.
void main(void) {
TRISD = 0x00; //port D set as output
LATD = 0x00; //port D output set LOW
unsigned int width = 1000; // length of T_on + T_off
unsigned int j;
unsigned int res;
while(1){
for (j = 1; j <= width; j++){
res = (unsigned int)((j*100)/width);
pwm(&LATD, res);
}
}
return;
}
void pwm(volatile unsigned char *lat, unsigned int cycle){
if(cycle > 100){ // reset the "cycle"
cycle = 100;
}
unsigned int i = 1;
while(i<=(cycle)){ // T_on
*lat = 0x01;
i++;
}
unsigned int j = 100-cycle;
while(j){ // T_off
*lat = 0;
j--;
}
return;
}
As for the program itself, it should work like so:
second parameter passed into pwm function is the duty cycle (in %) which changes from 0 to 100
with variable "width" the time needed for duty cycle to advance from 0% to 100% is controlled (width = 100 represents fastest time and everything above that is considered gradually slower time from 0% to 100%)
expression ((j*100)/width) serves as step variable inside "while" loop inside pwm function:
if width = 100, step is increased every increment of "j"
if width = 1000, step is increased every 10 increments of "j",
etc.
PORTD is passed into function as its address, whereas in function pwm, this address is operated via pointer variable lat
As for the problem itself, I could only assume two possibilities: either data type of second parameter of function pwm is incorrect or there is some unknown limitation within PIC microprocessor.
Also, here are definitions of configuration bits (device specific registers) of PIC, located int header file included in this program: https://imgur.com/a/UDYifgN
This is, how the program should operate: https://vimeo.com/488207207
This is, how the program currently operates: https://vimeo.com/488207746
The problem is a 16 Bit overflow:
res = (unsigned int)((j*100)/width);
if j is greater then 655 the result of the calculation j*100 is greater 16 Bit. Switch this to 32 Bit. Or easier make your loop from 0...100 for res.
e.g.
for (res = 0; res <= 100; res++){
pwm(&LATD, res);
}
I am trying to use Arduino to generate sin wave and gold code is used to determine when the wave will have a phase shift. However, the output is not performed as I expected. Sometimes, it does not occur any phase shift for consequent ten cycles, which should not happen according to our definition of gold code array. Which part of the code could I try to fix the problem?
int gold_code[]={1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1, 1,1,-1,1,1,1,-1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,1,1,1,-1,1,1,-1, -1, 1, 1,1,-1,-1,1,-1,-1,1,1,1};
void loop()
{
int n = sizeof(gold_code)/sizeof(gold_code[0]);
byte bsin[128];
int it;
unsigned long tm0;
unsigned int tm;
for(int i=0;i<128;i++)
{
bsin[i] = 8 + (int)(0.5 + 7.*sin( (double)i*3.14159265/64.));
}
int count=0;
int count1=0;
Serial.println(n);
tm0 = micros();
while(true)
{
tm = micros() - tm0;
if(tm > 511)
{
tm0 = tm0+512;
tm -= 512;
count++;
//Serial.println(gold_code[count%n]);
}
tm = (tm >> 2) ;
if(gold_code[count%n]==0){
PORTB = bsin[tm];
}
else{
PORTB = 16-bsin[tm];
}
}
}
The variable count eventually overflows and becomes negative. This, in conjunction with the modulo operation is a sign (pun intended) of a disaster waiting to happen.
Use a different method for limiting the value of count to the bounds of your gold_codearray.
You should expect a significant increase in frequency after removing the modulo operation, so you may need to add some pacing to your loop.
The pacing in your loop is wrong. Variable count increments 4 times as fast as your phase counter.
Also, #Edward Karak raises a valid point. To do a proper phase shift, you should add (or subtract) from tm, not from the sin value.
[EDIT] I was not quite happy with the way the phase shift is handled. It just doesn't feel right to advance the gold counter at the same pace as the phase counter. So I added a separate timer for that. Advances in the gold_code array every 8 microseconds for now, but you can change it to whatever you're supposed to have.
as in:
unsigned char tm0 = 0;
unsigned char tm0_gold = 0;
const unsigned char N = sizeof(gold_code) / sizeof(gold_code[0]);
unsigned char phase = 0;
for(;;)
{
// pacing for a stable frequency
unsigned char mic = micros() & 0xFF;
if (mic - tm0_gold >= 8)
{
tm0_gold = mic;
// compute and do the phase shift
if (++count >= N)
count -= N;
if (gold_code[count] > 0) // you have == 0 in your code, but that doesn't make sense.
phase += 16; // I can't make any sense of what you are trying to do,
// so I'll just add 45° of phase for each positive value
// you'll probably want to make your own test here
}
if (mic - tm0 >= 4)
{
tm0 = mic;
// advance the phase. keep within the LUT bounds
if (++phase >= 128)
phase -= 128;
// output
PORTB = bsin[phase];
}
}
For frequency stability, you will want to move the sine generator to a timer interrupt, after debugging. This will free up your loop() to do some extra control.
I don't quite understand why count increments as fast as the phase counter.
You may want to increment count at a slower pace to reach your goal.
I want to write a function for my AVR ATmega328 that debounces switches using state space to confirm a switch press. After finishing it I wanted to generalize my function so that I may reuse it in the future with little work, but that involves passing the pin I want to use as a function parameter, and I just can't get that to work.
This is what I have now:
int debounceSwitch(unsigned char *port, uint8_t mask)
{
int n = 0;
while (1)
{
switch (n)
{
case 0: //NoPush State
_delay_ms(30);
if(!(*port & (1<<mask))){n = n + 1;}
else {return 0;}
break;
case 1: //MaybePush State
_delay_ms(30);
if(!(*port & (1<<mask))){n = n + 1;}
else {n = n - 1;}
break;
case 2: //YesPush State
_delay_ms(30);
if(!(*port & (1<<mask))){return 1;}
else {n = n - 1;}
break;
}
}
}
I have a hunch my issue is with the data type I'm using as the parameter, and I seem to have gotten different answers online.
Any help would be appreciated!
Well in AVR ports are special IO registers and they are accessed using IN and OUT instructions. Not like memory using LDR etc.
From the port definition you can see that you need to make the port pointer volatile. which the compiler would have also told you as a warning when you would had tried to pass PORT to the function.
#define PORTB _SFR_IO8(0x05)
which maps to
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
Various issues:
The function should be void debounceSwitch(volatile uint8_t* port, uint8_t pin). Pointers to hardware registers must always be volatile. It doesn't make sense to return anything.
Never use 1 signed int literals when bit-shifting. Should be 1u << n or your program will bug out when n is larger than 8.
Burning away 30ms several times over in a busy-delay is horrible practice. It will lock your CPU at 100% doing nothing meaningful, for an eternity.
There are many ways to debounce buttons. The simplest professional form is probably to have a periodic timer running with interrupt every 10ms (should be enough, if in doubt measure debounce spikes of your button with a scope). It will look something like the following pseudo code:
volatile bool button_pressed = false;
void timer_interrupt (void)
{
uint8_t button = port & mask;
button_pressed = button && prev;
prev = button;
}
This assuming that buttons use active high logic.
What I dislike on your implementation is the pure dependency on PORT/IO handling and the actual filter/debouncing logic. What are you doing then, when the switch input comes over a signal e.g. from CAN?
Also, it can be handled much easier, if you think in configurable/parameterizable filters. You implement the logic once, and then just create proper configs and pass separate state variables into the filter.
// Structure to keep state
typedef struct {
boolean state;
uint8 cnt;
} deb_state_t;
// Structure to configure the filters debounce values
typedef struct {
uint8 cnt[2]; // [0] = H->L transition, [1] = L->H transition
} deb_config_t;
boolean debounce(boolean in, deb_state_t *state, const deb_config_t *cfg)
{
if (state->state != in) {
state->cnt++;
if (state->cnt >= cfg->cnt[in]) {
state->state = in;
state->cnt = 0;
}
} else {
state->cnt = 0;
}
return state->state;
}
static const deb_config_t debcfg_pin = { {3,4} };
static const deb_config_t debcfg_can = { {2,1} };
int main(void)
{
boolean in1, in2, out1, out2;
deb_state_t debstate_pin = {0, 0};
deb_state_t debstate_can = {0, 0};
while(1) {
// read pin and convert to 0/1
in1 = READ_PORT(PORTx, PINxy); // however this is defined on this architecture
out1 = debounce(in1, &debstate_pin, &debcfg_pin);
// same handling, but input from CAN
in2 = READ_CAN(MSGx, SIGxy); // however this is defined on this architecture
out2 = debounce(in2, &debstate_can, &debcfg_can);
// out1 & out2 are now debounced
}
Using a 8-bit AVR micro, I arrived to a simple situation which might not be that easy to solve.
Consider the following snippet:
static volatile uint8_t counter;
//fires often and I need all the values of the counter.
void isr(void) {
counter++;
}
int main (void) {
while(1) {
send_uart(counter);
counter = 0;
delay_ms(1000); //1 sec pause
}
return 0;
}
1.) It can happen that send_uart is followed by an isr which increases the counter, and then the next statement zeroes it out.
Therefore I'll miss one data from the counter.
2.) If I use ATOMIC_BLOCK(ATOMIC_RESTORESTATE) in the main fn, I can avoid the problems declared in (1), but it can happen that I miss an ISR because in this case INTs are disabled for a short time.
Is there a better way to pass information from the main fn to ISR?
If the counter is sampled rather than reset, there won't be any timing issues. Increments happening while sending will be accounted for in the next iteration. The unsigned data type of the counter variables will guarantee well-defined overflow behavior.
uint8_t cs = 0; // counter sample at time of sending
uint8_t n = 0; // counter as last reported
while (1) {
cs = counter; // sample the counter
send_uart((uint8_t)(cs - n)); // report difference between sample and last time
n = cs; // update last reported value
delay_ms(1000);
}
When I execute this program, the led blinks for 1s, then 2s, then loops:
#include <htc.h>
#include <pic16f877.h>
#define _XTAL_FREQ 4e6
int count;
int check(int count);
void main(void){
count = 0;
TRISD = 0xBF;
count=check(count);
count=check(count);
}
int check(count){
if(count == 0){
/* blink an led for 1s */
++count;
}else if(count == 1){
/* blink an led for 2s */
++count;
}
}
But when I execute this program, 2 things happen:
If I execute this program right after I had executed the previous one, the led blinks for 1s, then 2s then stays off.
If I execute this program at any other time, once it's not right after the previous one, the led stays off; doesn't even blink.
#include <htc.h>
#include <pic16f877.h>
#define _XTAL_FREQ 4e6
int check(int count);
int count = 0;
void main(void){
TRISD = 0xBF;
count=check(count);
count=check(count);
}
int check(count){
if(count == 0){
/* blink an led for 1s */
++count;
}else if(count == 1){
/* blink an led for 2s */
++count;
}
}
So I am wondering what this behaviour has to do with me declaring my variables locally vs globally.
For all practical purposes, the two programs are completely equivalent. You do not declare variables locally vs. globally; the count variable is global in both programs. The only difference is that the count variable is set to zero in the first program by an instruction. But it was already zero because it is global and global variables are initialized to zero at load time. If you leave out the count = 0 statement from the first program they have become identical.
As they are identical but show different behavior, the problem must be in the mplab emulator. Use the step feature of the emulator/IDE to check the value of count in the check function.
All suggestions in the comments to your question improve the code but none are required:
a parameter without a type is an int by defaut. So the count parameter is an int;
a return statement would ensure the right value is returned, but the register in which the function return value is carried apparently still holds the incremented value of count, in Intel assembler this is the ax register:
mov ax, [count]
inc ax
mov [count], ax