I am working on an MCU where each GPIO port has 16 pins. I have an interrupt routing where I need to see if the input data registers of pins 14, 13 and 12 are high or low. I created this simple test scenario to see if I can read and store that specific pins in a uint8_t variable:
#include <stdio.h>
#include <stdint.h>
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */
int main() {
uint32_t maskWithOR = GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_12;
uint32_t maskInBinary = 0b00000000000000000111000000000000;
uint32_t data[8] = {
//.................XXX............
0b10010000100011110000000011111111, //0 = 000
0b10010000100011110001000011111111, //1 = 001
0b10010000100011110010000011111111, //2 = 010
0b10010000100011110011000011111111, //3 = 011
0b10010000100011110100000011111111, //4 = 100
0b10010000100011110101000011111111, //5 = 101
0b10010000100011110110000011111111, //6 = 110
0b10010000100011110111000011111111, //7 = 111
};
printf("maskWithOR = 0x%x\r\n", maskWithOR);
printf("maskInBinary = 0x%x\r\n", maskInBinary);
printf("\r\nOR MASK:\r\n");
for(int i = 0; i < 8; i++) {
uint8_t result = data[i] & maskWithOR;
printf("result[%d] = %d\r\n", i, result);
}
printf("\r\nBINARY MASK:\r\n");
for(int i = 0; i < 8; i++) {
uint8_t result = data[i] & maskInBinary;
printf("result[%d] = %d\r\n", i, result);
}
return 0;
}
This is the output of my test program:
maskWithOR = 0x7000
maskInBinary = 0x7000
OR MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0
BINARY MASK:
result[0] = 0
result[1] = 0
result[2] = 0
result[3] = 0
result[4] = 0
result[5] = 0
result[6] = 0
result[7] = 0
What am I doing wrong?
You are storing the result of a 32-bit operation in an 8-bit variable:
uint8_t result = data[i] & maskWithOR;
The result of this operation is that the value is truncated, leaving you with the last eight bits of the original result. Since all three bits of interest to you are above bit 12, the results that you get are always zero.
If you must fit the result in eight bits, shift the value of data[i] & maskWithOR by the index of the lowest bit, i.e. by 12.
You cannot store your AND result in an 8 bit integer...
You could try forcing a boolean result (1 or 0) like this:
uint8_t result = (data[i] & maskWithOR)>0;
After reviewing your desired output value from 0 - 7, you could force a bit shift in your 32 bit unsigned number...12 bits to the right and then mask with only the bits that fit into an 8 bit integer to ensure you get an 8 bit result
uint8_t result = ((data[i] & maskWithOR)>>12) & 255;
Although the 255 mask is a bit redundant...You can do it like this and probably get away with it ...
uint8_t result = (data[i] & maskWithOR)>>12;
But as #chux mentioned ANDing with 255 will quiet or suppress warnings that arise from narrowing the result from uint32_t to uint8_t
Related
I'm trying to convert this code to be able to generate random numbers 1-56.
I would understand, but because the program has to switch back and forth to be able to show both digits, I'm confused.
I know in some respect, I can use rand() to choose.
I will eventually use this code in junction with an lcd screen to display the numbers as well as the dual seven segment display, but for now, just trying to figure out to program a PIC16F684 to generate the random number on the dua84l seven seg display
Below is the circuit and code.
Not included in the diagram, but in the code is RA3 & RA4 have buttons that clear the display or generate the next digit.
The program supplied displays 00-0xFF as a button gets pushed. It may be easier to rewrite the program, but I just dont understand it
#include <xc.h>
/*
*
*
* 6/30/2020
/******************************************/
/* ------------------------------------------- */
/* Software/Hardware Interface: */
/* ------------------------------------------- */
/* */
/* Select Right Digit using >> RA0 */
/* Select Left Digit using >> RA1 */
/* */
/* Segment a >> RA5 */
/* Segment b >> RC5 */
/* Segment c >> RC4 */
/* Segment d >> RC3 */
/* Segment e >> RC2 */
/* Segment f >> RC1 */
/* Segment g >> RC0 */
/* ------------------------------------------- */
void PORTA_init(void)
{
PORTA = 0; // All PORTA Pins are low
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
//TRISA = 0b001111; // RA4 and 5 are outputs; RA0,1,2, and 3 are input
return;
}
/******** END OF PORTA_init ****************************/
void delay_routine(void)
{
int i, j;
for (i = 0; i<2000; i++);
for (j = 0; j <2000;j++);
return;
}
/******** END OF delay_20ms *************************/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
int i, j;
int DisplayValue, DisplayLED;
const char LEDDigit[] = {
0b0000001, // "0"
0b1001111, // "1"
0b0010010, // "2"
0b0000110, // "3"
0b1001100, // "4"
0b0100100, // "5"
0b0100000, // "6"
0b0001111, // "7"
0b0000000, // "8"
0b0001100, // "9"
0b0001000, // "A"
0b0000000, // "b"
0b0110001, // "C"
0b0000001, // "d"
0b0110000, // "E"
0b0111000
}; // "F"
main()
{
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
TRISA = 0b011101; // RA5 and RA1 are outputs
TRISC = 0b000000;
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
while(1 == 1) // Loop Forever
{
if (0 == DisplayLED) // True, then display right digit
{
RA5 = LEDDigit[DisplayValue & 0x0F] >> 6;
// Clears display bits 4 - 7 of DisplayValue,
// then selects bit 7 of LEDDigit
PORTC = LEDDigit[DisplayValue & 0x0F] & 0x03F;
// clears display bits 4 - 7 of DisplayValue,
// then selects bits 0 - 6 of LEDDigit
}
else
{
RA5 = LEDDigit[(DisplayValue >> 4) & 0x0F] >> 6;
PORTC = LEDDigit[(DisplayValue >> 4) & 0x0F] & 0x03F;
} //
TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
NOP(); // Used for 10 ms Timing
for (i = 0; i < 30; i++);//10ms Delay Loop
NOP(); // Used for 10 ms Timing
if (RA3 == 0)
{
delay_routine();
DisplayValue++; // Increment the Counter
delay_routine();
} //
if (RA4 == 0)
{
delay_routine();
DisplayValue=0;
delay_routine();
}
}
}
#tjpplay,
The code you posted has some subtle issues and a failure to alternate the digit driver enables.
Your method to detect a button press disrupts the digit multiplexer timing and causes flicker.
With the digit drivers connected to the PGC and PGD pins used for In-Circuit-Serial-Programmer(ICSP) makes in circuit programming difficult. In-Circuit-Debug(ICD) will not work with this implementation.
The code avoids the Read-Modify-Write(RMW) trap for new players by only using 8-bit writes to the PORTA and PORTC registers.
Using syntax that allows the C compiler to do single bit sets and clears can have a RMW issue for controllers like the PIC16F684 especially when driving LED directly.
I think that this code may work with your hardware:
/*
* File: main.c
* Author: dan1138
* Target: PIC16F684
* Compiler: XC8 v2.20
* IDE: MPLABX v5.25
*
* Description:
*
* Created on July 21, 2020, 3:45 PM
*
* PIC16F684
* +------------:_:------------+
* GND -> 1 : VDD VSS : 14 <- 5v0
* SEG_a_DRIVE <> 2 : RA5/T1CKI PGD/AN0/RA0 : 13 <> DIGIT_DRIVE_2
* SW2 <> 3 : RA4/AN3 PGC/AN1/RA1 : 12 <> DIGIT_DRIVE_1
* SW1 -> 4 : RA3/VPP AN2/RA2 : 11 <>
* SEG_b_DRIVE <> 5 : RC5/CPP1 AN4/RC0 : 10 <> SEG_g_DRIVE
* SEG_c_DRIVE <> 6 : RC4/C2OUT AN5/RC1 : 9 <> SEG_f_DRIVE
* SEG_d_DRIVE <> 7 : RC3/AN7 AN6 RC2 : 8 <> SEG_e_DRIVE
* +---------------------------:
* DIP-14
*/
// CONFIG --- Configuration Word --- START
#pragma config FOSC = INTOSCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG --- Configuration Word --- END
#include <xc.h>
#include <stdlib.h>
/* Oscillator frequency we will select with the OSCCON register */
#define _XTAL_FREQ (4000000ul)
/*
* Segment locations
* of an LED display
* ---a---
* : :
* f b
* : :
* ---g---
* : :
* e c
* : :
* ---d---
*/
const unsigned char LEDDigit[] = {
// abcdefg, Segment on = 0
0b00000001, // "0"
0b01001111, // "1"
0b00010010, // "2"
0b00000110, // "3"
0b01001100, // "4"
0b00100100, // "5"
0b00100000, // "6"
0b00001111, // "7"
0b00000000, // "8"
0b00001100, // "9"
0b00001000, // "A"
0b01100000, // "b"
0b00110001, // "C"
0b01000010, // "d"
0b00110000, // "E"
0b00111000 // "F"
};
void main(void)
{
unsigned char DisplayValue, DisplayLED, DigitSegments;
unsigned char LoopCount;
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
__delay_ms(500); // wait for ICD before making PGC and PGD outputs;
TRISA = 0b011100; // RA5, RA1, RA0 are outputs
TRISC = 0b000000;
OPTION_REGbits.nRAPU = 0; // Enable weak pull-up on PORTA
WPUA = 0; // Turn off all pull-ups
WPUAbits.WPUA4 = 1; // Turn on RA4 pull-up
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
LoopCount = 0;
for(;;)
{
PORTC = 0xFF; // turn off all segment drivers
PORTA = 0xFF; // and digit drivers
if (1 == (DisplayLED & 1))
{
DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111110; // turn on Digit driver 2
}
else
{
PORTA = 0b011110; // turn on Digit driver 2 and SEG_a_DRIVER
}
}
else
{
DigitSegments = LEDDigit[DisplayValue & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111101; // turn on Digit driver 1
}
else
{
PORTA = 0b011101; // turn on Digit driver 1 and SEG_a_DRIVER
}
}
PORTC = DigitSegments; // turn on segment drivers b to g
DisplayLED++; // select next digit
__delay_ms(10); // Show digit for 10 milliseconds
if(0 == PORTAbits.RA3) // is SW1 pressed?
{
LoopCount++;
if(LoopCount == 1)
{
DisplayValue++; // Increment display value every 500 milliseconds
}
if(LoopCount >= 50)
{
LoopCount = 0;
}
}
else
{
LoopCount = 0;
}
if(0 == PORTAbits.RA4) // is SW2 pressed?
{
DisplayValue = 0; // Reset display value to zero
LoopCount = 0;
}
}
}
This is how I would chnage the above code to produce the random numbers you asked for:
void main(void)
{
unsigned char DisplayValue, DisplayLED, DigitSegments;
unsigned char LoopCount;
unsigned int Temp;
PORTA = 0;
PORTC = 0;
CMCON0 = 7; // Turn off Comparators
ANSEL = 0; // Turn off ADC
__delay_ms(500); // wait for ICD before making PGC and PGD outputs;
TRISA = 0b011100; // RA5, RA1, RA0 are outputs
TRISC = 0b000000;
OPTION_REGbits.nRAPU = 0; // Enable weak pull-up on PORTA
WPUA = 0; // Turn off all pull-ups
WPUAbits.WPUA4 = 1; // Turn on RA4 pull-up
DisplayValue = 0; // Start Displaying at 0x00
DisplayLED = 0; // Display the 1s first
LoopCount = 0;
srand(0x1234);
for(;;)
{
PORTC = 0xFF; // turn off all segment drivers
PORTA = 0xFF; // and digit drivers
if (1 == (DisplayLED & 1))
{
DigitSegments = LEDDigit[(DisplayValue >> 4) & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111110; // turn on Digit driver 2
}
else
{
PORTA = 0b011110; // turn on Digit driver 2 and SEG_a_DRIVER
}
}
else
{
DigitSegments = LEDDigit[DisplayValue & 0x0F];
if(DigitSegments & 0b1000000)
{
PORTA = 0b111101; // turn on Digit driver 1
}
else
{
PORTA = 0b011101; // turn on Digit driver 1 and SEG_a_DRIVER
}
}
PORTC = DigitSegments; // turn on segment drivers b to g
DisplayLED++; // select next digit
__delay_ms(10); // Show digit for 10 milliseconds
if(0 == PORTAbits.RA3) // is SW1 pressed?
{
LoopCount++;
if(LoopCount == 1)
{
// Display a new random value every 500 milliseconds
Temp = rand() & 0xFFu; // put random value in range of 0 to 255 and treat is as a fraction in range (0/256) <= value < (255/256)
Temp = (Temp * 56u + 0x100u) >> 8; // Use tricky math to make a random number in the range from 1 to 56
DisplayValue = (Temp / 10u) << 4; // Extract the ten's digit
DisplayValue = DisplayValue | (Temp % 10); // Extract the one's digit
}
if(LoopCount >= 50)
{
LoopCount = 0;
}
}
else
{
LoopCount = 0;
}
if(0 == PORTAbits.RA4) // is SW2 pressed?
{
DisplayValue = 0; // Reset display value to zero
LoopCount = 0;
}
}
}
Your digits are BCD coded(BinaryCodedDecimal), each digit 0-9 is coded in four bits 0000-1001.
DisplayLED toggles between 0 and 1, to select which digit to display, you must ensure you don't update the random value until it have been displayed, actually you should probably update it even more seldom as the display relays on the after glow in the LED and our slow eyes to display an image.
if (DisplayLED == 0) {
uint8_t r = myrand(); // place your favorite random generator here.
DisplayValue = (r/10)<<4|(r%10);
}
Pin 0 and 1 on PortA are flipped by turning them to input and output respectively
TRISA = TRISA ^ 0b000011; // Swap Left/Right (RA0 and RA1)
PORTA = PORTA & 0b111100; // Make Sure Bits are Low
DisplayLED = DisplayLED ^ 1; // Other Digit Next
Since the least significant bits in TRISA are initiated as 01 they will alternate when negated only one of them is always an output.
I am in the process of building a drum machine and I want to have two 16 bit arrays defining the state of the machine. One array "current_led" which has a 1 set at the index corresponding to the current 16th note being played.
When the user programs a sound to be played, for instance at step 1 and 4, I want one 16 bit array "selected_steps" to have a 1 set at index 0 and 3.
So I want, at each step update defined by the beats per minute, the "current_led" to shift the bit but the "selected_steps" is static.
I want a final array "led_array" which is constructed by
led_array = XOR(selected_steps,current_led)
This is such that I can use a shift register to light up the correct LED's at each step update.
But since I have some trouble defining and working with bits and arrays in C I do not understand how to initialize the arrays correctly and work with them.
What I would want it something like
int current_led[16];
int selected_steps[16];
int led_array[16];
//Function is called every 0.5 s if BPM 120.
void step(void) {
step_number = step_number < 15 ? step_number +1 : 0;
}
I am using 2 PISO shift registers to take the input from 16 buttons to my micro controller. I have the parallell load pin set to high constantly, such that whenever the user pushes a button, that corresponding pin on the shift register is set to 1. Therefore I am reading each 16 pins every time to see if the user has pushed down any buttons.
//Check which steps are selected by the user. This function is called every 1 ms
void scan_buttons() {
for (int j = 0; j<16 ; j++) {
if (PIND & 0b01000000){
selected_steps[j] = 1;
} else {
selected_steps[j] = 0;
}
void update_led(void) {
current_led = (1 << step_number);
led_array = current_led^selected_steps;
for (int j = 15; j>=0 ; j--) {
if (led_array[j] == 1) {
do something...
} else {
do something else...
}
}
}
So for clarity, here is an example of how the LED's should represent that state.
If the BPM is set to 120, and we have 16 steps (4 beats), the step should increment every 60/BPM seconds (0.5 seconds). The current step is indicated by a bright LED. I also indicate to the user which step he/she has programmed a sound on by always having the LED light up at that current step.
Step 1: step_number = 0
LED: [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
Step 2: step_number = 1
LED: [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
Step 3: step_number = 2, selected_step[7] = 1, selected_step[11] = 1,
(User has chosen to input a sound on step 8 and 12 by pressing button 8 and 12)
LED: [0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0]
Step 4: step_number = 3, selected_step[7] = 1, selected_step[11] = 1,
(User has not pressed any buttons since last step)
LED: [0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0]
But I do not understand how to declare the arrays, and write the correct code to set the bits correctly and perform XOR operations.
Here is how you may set and clear bits in a uint16_t (the same goes for any unsigned ints, just change the types accordingly)
It is a long time since i have done any bit-manipulations, so you should double check this
before you use it, don't have any time to do it myself.
/*
`set_bits`, `unset_bits` and `flip_bits` modifies multiple bits in v.
The bits you want to modify are selected by setting the corresponding bit
in `mask` to 1.
*/
uint16_t set_bits(uint16_t v, uint16_t mask)
{
return v | mask;
}
uint16_t unset_bits(uint16_t v, uint16_t mask)
{
return v & ~mask;
}
uint16_t flip_bits(uint16_t v, uint16_t mask)
{
return v | ((~v) & mask)
}
/*
`set_bit`, `unset_bit`, `flip_bit`, `overwrite_bit` modifies a single bit in `v`.
The bit to modify is given by the index `i`
*/
uint16_t set_bit(uint16_t v, int i)
{
return set_bits(v, 1 << i);
}
uint16_t unset_bit(uint16_t v, int i)
{
return unset_bits(v, 1 << i);
}
uint16_t flip_bit(uint16_t v, int i)
{
return flip_bits(v, 1 << i);
}
uint16_t overwrite_bit(uint16_t v, int i, int new_val)
{
/* ensure `new_val` is either 0 or 1 */
new_val = new_val ? 1 : 0;
uint16_t mask = 1 << i;
uint16_t mask_x = ~mask;
uint16_t nv = new_val << i;
return v & (mask_x | nv);
}
int read_bit(uint16_t v, int i)
{
uint16_t mask = 1 << i;
return (v & mask) ? 1 : 0;
}
/* How to initialize all the bits in `selected_steps` to zero */
selected_steps = 0;
/* How to initialize all the bits in `selected_steps` to 1 */
selected_steps = 0xffff; /* or = 0b1111111111111111 */
/* How to read the value of bit 8 in `selected_step` */
int val = read_bit(selected_steps, 8);
/* How to set the value of bit 8 to 1 */
selected_steps = set_bit(selected_steps, 8);
/* or */
selected_steps = overwrite_bit(selected_steps, 8, 1);
/* or */
selected_steps = set_bits(selected_steps, 0b100000000);
/* How to set the value of bit 8 to 0 */
selected_steps = unset_bit(selected_steps, 8);
/* or */
selected_steps = overwrite_bit(selected_steps, 8, 0);
/* or */
selected_steps = unset_bits(selected_steps, 0b100000000);
/* Setting bits 1 and 4 to 1 */
selected_steps = set_bits(selected_steps, 0b10010);
/* or */
selected_steps = set_bits(selected_steps, (1<<4) | (1<<1));
/* Calculating xor of two bitsets */
uint16_t xor_a_b = a ^ b;
Depending of your use case, you may choose to define these functions as static inline. It may also make sense to turn step_number into a mask rather than index.
My task is to take a functional program written by my instructor in assembly language and convert it to C language. The program is written for the TI MSP430G2553, and utilizes an attached 4-digit LED display with three side-by-side push-buttons. The display is supposed to start blank. When the right button is pressed, "ECE-3362" will begin to scroll across the display from right to left.
My conversion is 'complete' as far as I can tell and the code compiles with no errors. However, the push-buttons do not have any visible effect and the display remains blank.
I do get a few "Integer conversion resulted in truncation" warnings, but I'm not sure of the effect of this on the functionality of the program. At most I would assume this would cause the display to show the wrong values if part of my constant definitions get truncated.
One part of my code that is particularly suspicious to me is my port2 interrupt service routine at the very bottom (mainly the PB & P2_IFG comparisons). I didn't fully comprehend what was going on in my instructor's assembly version of that section, so something important may have been lost in translation.
I am new to assembly in general, and C as far as microcontrollers go. I was leaning heavily on my instructors example code as a reference. I'll put my code below, and I have my instructor's code on hand if anyone would like to see it.
I know the rules say not to post entire files but as far as I can tell I could have a mistake or more just about anywhere in the program.
My code:
#include <msp430g2553.h>
//-----------------------------------------------------------------------------
// Definition of Constants
//-----------------------------------------------------------------------------
#define TIMER_A0_COUNT_1 2000 //2000
#define TIMER_A1_COUNT_1 50000 //50000
#define MAX_TIMER_COUNT 10 //10
#define LONG_DELAY (0xFFFF) //65535
//definitions of segment positions
#define SEG_A (0x01u) // 00000001 Port pin position P1.0
#define SEG_B (0x02u) // 00000010 Port pin position P1.1
#define SEG_C (0x04u) // 00000100 Port pin position P1.2
#define SEG_D (0x08u) // 00001000 Port pin position P1.3
#define SEG_E (0x10u) // 00010000 Port pin position P1.4
#define SEG_F (0x20u) // 00100000 Port pin position P1.5
#define SEG_G (0x40u) // 01000000 Port pin position P1.6
#define SEG_DP (0x80u) // 10000000 Port pin position P1.7
//since inverted pattern is needed for the display, this defines inverse pattern
#define SEG_A_N ~SEG_A // Port pin position P1.0
#define SEG_B_N ~SEG_B // Port pin position P1.1
#define SEG_C_N ~SEG_C // Port pin position P1.2
#define SEG_D_N ~SEG_D // Port pin position P1.3
#define SEG_E_N ~SEG_E // Port pin position P1.4
#define SEG_F_N ~SEG_F // Port pin position P1.5
#define SEG_G_N ~SEG_G // Port pin position P1.6
#define SEG_DP_N ~SEG_DP // Port pin position P1.7
//NOTE: display board requires INVERSE of these patterns due to Active LOW
#define DIG_3 (0x01u) // 00000001 Port pin position P2.0 (MSdigit)
#define DIG_2 (0x02u) // 00000010 Port pin position P2.1
#define DIG_1 (0x04u) // 00000100 Port pin position P2.2
#define DIG_0 (0x08u) // 00001000 Port pin position P2.3(LSdigit)
#define DP_COM (0x10u) // 00010000 Port pin position P2.4
//since inverted pattern is needed for the display, this defines inverse pattern
#define DIG_3_N ~DIG_3 // Port pin position P2.0 (MSdigit)
#define DIG_2_N ~DIG_2 // Port pin position P2.1
#define DIG_1_N ~DIG_1 // Port pin position P2.2
#define DIG_0_N ~DIG_0 // Port pin position P2.3(LSdigit)
#define DP_COM_N ~DP_COM // Port pin position P2.4
//Pushbutton assignments CORRECTED to compensate for board layout swap
#define PB_0 (0x20u) // 00100000 Port pin position P2.5 RightMost button
#define PB_1 (0x80u) // 10000000 Port pin position P2.7 Middle button
#define PB_2 (0x40u) // 01000000 Port pin position P2.6 LeftMost button
#define SEG_PORT P1OUT
#define DIG_PORT P2OUT
#define PB_PORT P2IN
//NOTE: display bd requires the INVERSE of these patterns due to Active LOW
#define ONE (0x06u) // 00000110
#define TWO (0x5Bu) // 01011011
#define THREE (0x4Fu) // 01001111
#define FOUR (0x66u) // 01100110
#define FIVE (0x6Du) // 01101101
#define SIX (0x7Du) // 01111101
#define SEVEN (0x03u) // 00000111
#define EIGHT (0x7Fu) // 01111111
#define NINE (0x67u) // 01100111
#define ZERO (0x3Fu) // 00111111
//since inverted pattern is needed for the display, this defines inverse pattern
#define ONE_N (~0x06u) // ~00000110
#define TWO_N (~0x5Bu) // ~01011011
#define THREE_N (~0x4Fu) // ~01001111
#define FOUR_N (~0x66u) // ~01100110
#define FIVE_N (~0x6Du) // ~01101101
#define SIX_N (~0x7Du) // ~01111101
#define SEVEN_N (~0x03u) // ~00000111
#define EIGHT_N (~0x7Fu) // ~01111111
#define NINE_N (~0x67u) // ~01100111
#define ZERO_N (~0x3Fu) // ~00111111
//other figures for scrolling display
#define E_N (~0x79u) // ~01111001
#define C_N (~0x39u) // ~00111001
#define DASH_N (~0x40u) // ~01000000
#define BLANK_N (~0x00u) // ~00000000
//------------------------------------------------------------------------------
// Definition of Variables
//------------------------------------------------------------------------------
int DisplayValue = 0; // contains 4 digit value to display in BCD format
// BCDdig3 | BCDdig2 | BCDdig1 | BCDdig0
// xxxx xxxx xxxx xxxx
char CurrentDigitPos = 0; // global variable used by WriteDigitToDisplay ISR
// holds digit position of current digit to write
char CurrentDigitValue = 0; // global variable used by WriteDigitToDisplay ISR
// holds digit value of next digit to write
char StartFlag = 0; // Boolean state flags
char PauseFlag = 0;
char ContinueFlag = 0;
char ScrollingStateFlag = 0;
char PB_0_Mode = 0;
char PB_1_Mode = 0;
char PB_2_Mode = 0;
char Hundred_mS = 0;
char TotalINTCount1 = 0;
int PatternsToScroll[12] = {0x0000, 0x0006, 0x0065, 0x0656, 0x6561, 0x5613,
0x6133, 0x1334, 0x3342, 0x3420, 0x4200, 0x2000};
char PatternsIndex = 0;
int CurrentPattern = 0;
char PatternsLeft = 12;
char SegPatterns[7] = {BLANK_N, DASH_N, TWO_N, THREE_N, SIX_N, C_N, E_N};
//-----------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------
void WriteNextDigitToDisplay(int DisplayValue, char CurrentDigitPos, char CurrentDigitValue)
{
int DisplayValueCopy = 0; // initialize function variable
DIG_PORT |= DIG_0+DIG_1+DIG_2+DIG_3+DP_COM; // eliminate ghosting
if ((CurrentDigitPos - 0) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x000F;
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_0_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 1) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x00F0;
DisplayValueCopy >>=4; //rra 4 times to get val into LSnibble
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_1_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 2) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0x0F00;
DisplayValueCopy = __swap_bytes(DisplayValueCopy);
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_2_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 3) == 0)
{
DisplayValueCopy = DisplayValue;
DisplayValueCopy &= 0xF000;
DisplayValueCopy = __swap_bytes(DisplayValueCopy);
DisplayValueCopy >>=4;
SEG_PORT = SegPatterns[DisplayValueCopy];
DIG_PORT = DIG_3_N;
CurrentDigitPos++;
}
if ((CurrentDigitPos - 4) == 0)
{
CurrentDigitPos = 0;
}
}
void delay()
{
for (int i = 0; i < LONG_DELAY; i++);
}
int main( void )
{
//---------------------------------------------------------------------------
// Setup
//---------------------------------------------------------------------------
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
// Setup Port 1 (all outputs for segment display)
P1DIR = SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G + SEG_DP;
// Setup Port 2
P2DIR = 0x1F; // (00011111 : 3MSbits as inputs (pushbuttons) 5LSbits as outputs)
P2OUT = PB_0 + PB_1 + PB_2; // 11100000 or 0xE0 defines pushbutton positions
P2REN |= PB_0 + PB_1 + PB_2; // turn on internal pull-up for the pushbuttons
// Activate the General Purpose Digital I/O mode for P2.6 and P2.7
P2SEL &= ~PB_1 + ~PB_2;
// Setup Port 2 interrupts for the pushbuttons
P2IE |= PB_0 + PB_1 + PB_2;
P2IES |= PB_0 + PB_1 + PB_2;
// Turn off all the segments and digits
SEG_PORT = 0xFF;
DIG_PORT = 0xFF;
// SetupCalibratedClock
// Set up the clock (calibrated mode at 1 MHz)
// Get the calibrated data for the DCO clock
// Set DCO to 1 MHz: (this directly from TI Family Guide page283 and 284
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
// Set up Timers
// TimerA0
TA0CCR0 = TIMER_A0_COUNT_1; // load a count "up to"value into timer
TA0CTL = TASSEL_2+ID_3 + MC_1; // SMCLK, input div = 8, upmode
TA0CCTL0 = CCIE; // interrupt enabled for Timer0
// TimerA1
TA1CCR0 = TIMER_A1_COUNT_1; // load a count "up to"value into timer
TA1CTL = TASSEL_2+ID_3 + MC_1; // SMCLK, input div = 8, upmode
TA1CCTL0 = CCIE; // interrupt enabled for Timer1
// Start of main program
// Initialize Boolean state flags and some other variables
StartFlag = 0;
PauseFlag = 0;
ContinueFlag = 0;
ScrollingStateFlag = 0;
PB_0_Mode = 0;
PB_1_Mode = 0;
PB_2_Mode = 0;
DisplayValue = 0;
// Clear Interrupt Flags
P1IFG = 0; // clear the Int flag register for Port 1
P2IFG = 0; // clear the Int flag register for Port 2
// Enable General Interrupts
_BIS_SR(GIE); // enable the general interrupts bit
//----------------------------------------------------------------------------
// Top of main program loop structure
//----------------------------------------------------------------------------
while(1) // forever loop
{
// test the Pushbutton mode Boolean variables to see what to do
if ((PB_0_Mode - 1) == 0) // (START CONDITION)
{
// Rightmost button (START)
PB_0_Mode = 0;
ScrollingStateFlag = 1; // make it TRUE
PatternsIndex = 0; // beginning of pattern array
PatternsLeft = 12;
CurrentPattern = PatternsToScroll[PatternsIndex]; // might be redundant
}
if ((PB_1_Mode - 1) == 0) // (CONTINUE CONDITION)
{
// Middle button (CONTINUE)
PB_1_Mode = 0;
ScrollingStateFlag = 1; // make it TRUE
}
if ((PB_2_Mode - 1) == 0) // (PAUSE CONDITION)
{
// Leftmost button (PAUSE)
PB_2_Mode = 0;
ScrollingStateFlag = 0; // make it FALSE
}
else
{
if ((ScrollingStateFlag - 1) == 0)
{
CurrentPattern = PatternsToScroll[PatternsIndex];
DisplayValue = CurrentPattern; // save pattern array element
PatternsIndex++; // move to next element
PatternsLeft--; // one less pattern to display
if ((PatternsLeft - 0) == 0) // done all the patterns --> reset variables
{
PatternsIndex = 0;
CurrentPattern = PatternsToScroll[PatternsIndex]; // might be redundant
PatternsLeft = 12;
}
delay(); // update the scrolling slowly
delay();
}
}
}
return 0;
} // end of MAIN
//------------------------------------------------------------------------------
// Subroutines
//------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// WriteNextDigitToDisplay
// passed in - DisplayValue, CurrentDigitPos
// returned - nothing
// accomplishes - Writes next digit to the expansion bd display
// uses: R15, global variable CurrentDigitPos, CurrentDigitValue
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// Interrupt Service Routines
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// Interrupt Service Routine for Timer_A 1
// Passed in: nothing
// Activated every time TimerA_1 times out
// Updates global variable TotalINTCount1 to keep track of number of TimerA_1
// interrupt events
// Uses: nothing except modifies global variable TotalINTCount
// For this example, set up to trigger every 100 mS
//-------------------------------------------------------------------------------
//Timer0_A0 ISR
#pragma vector=TIMER0_A0_VECTOR // this line tells the C compiler to put
// the start address of the following ISR
// into the Interupt Vector table
__interrupt void Timer_A0_ISR (void) // required syntax for first line of ISR
{
WriteNextDigitToDisplay(DisplayValue, CurrentDigitPos, CurrentDigitValue);
}
//Timer0_A1 ISR
#pragma vector=TIMER1_A1_VECTOR // this line tells the C compiler to put
// the start address of the following ISR
// into the Interupt Vector table
__interrupt void Timer_A1_ISR (void) // required syntax for first line of ISR
{
Hundred_mS++;
TotalINTCount1++;
}
// Port2_ISR
// passed in - nothing
// returned - nothing
// accomplishes - updates global Boolean variables for Pushbutton status
// uses: nothing
//-------------------------------------------------------------------------------
//Port2_ISR
// if we get to here, an interrupt occurred on the Port 2
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
if ((PB_0 & P2IFG) == 1)
{
PB_0_Mode |= 1;
PB_1_Mode &= ~1;
PB_2_Mode &= ~1;
}
if ((PB_1 & P2IFG) == 1)
{
PB_0_Mode &= ~1;
PB_1_Mode |= 1;
PB_2_Mode &= ~1;
}
if ((PB_2 & P2IFG) == 1)
{
PB_0_Mode &= ~1;
PB_1_Mode &= ~1;
PB_2_Mode |= 1;
}
P2IFG = 0;
}
Can't post instructor's entire code due to character limit. Here is his port 2 ISR:
; Port2_ISR
; passed in - nothing
; returned - nothing
; accomplishes - updates global Boolean variables for Pushbutton status
; uses: nothing
;-------------------------------------------------------------------------------
Port2_ISR
; if we get to here, an interrupt occurred on the Port 2
bit.b #PB_0, &P2IFG ; PB_0 Pushbutton? (if 1 it is pressed)
jnz PB_0_Case ; it is PB_0
;no so try the next case
bit.b #PB_1, &P2IFG ; PB_1 Pushbutton? (if 1 it is pressed)
jnz PB_1_Case ; it is PB_1
;no so try the next case
bit.b #PB_2, &P2IFG ; PB_2 Pushbutton? (if 1 it is pressed)
jnz PB_2_Case ; it is PB_2
jmp DoneWithPort_2_ISR ; no, so don't do anything
PB_0_Case
bis.b #1, &PB_0_Mode
bic.b #1, &PB_1_Mode ;clear other modes
bic.b #1, &PB_2_Mode
jmp DoneWithPort_2_ISR
PB_1_Case
bis.b #1, &PB_1_Mode
bic.b #1, &PB_0_Mode ;clear other modes
bic.b #1, &PB_2_Mode
jmp DoneWithPort_2_ISR
PB_2_Case
bis.b #1, &PB_2_Mode
bic.b #1, &PB_1_Mode ;clear other modes
bic.b #1, &PB_0_Mode
jmp DoneWithPort_2_ISR
DoneWithPort_2_ISR
clr.b &P2IFG ; clear the flag so system is ready for another interrupt
reti ; return from interrupt
;-------------------------------------------------------------------------------
; end of Port2_ISR
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
You have set all your PB_N_MODE to 0 and checking if subtracting 1 to those will equate to 0, can't you set them to 1 or perhaps check if they equate to -1?
PB_1_MODE = 1
PB_2_MODE = 1
...
#define PB_0 (0x20u)
if ((PB_0 & P2IFG) == 1)
The value of the expression PB_0 & P2IFG is either 0x20 or 0; it can never be 1.
All your ifs have the same structure (if ((x) == 0) or if ((x) == 1)), which is confusing and can lead to errors. You should treat the x properly as a boolean expression, and use if (x) to check for a non-zero value, or if (!(x)) for zero.
I am currently trying to make a Random Number Generator using a MSP430 (MSP43 G2553) and then create an algorithm for a Pseudo Random Number Generator. I have a code for these two processes and also a code used to test the programs with LEDs.
For some reason, I encounter some errors that I cannot seem to resolve. I will attach the codes and the errors to get a second opinion on the syntax.
#include <msp430g2553.h>
#include "rand.h"
/**
* Random number generator.
*
* NOTE: This affects Timer A.
*
* Algorithm from TI SLAA338:
* http://www.ti.com/sc/docs/psheets/abstract/apps/slaa338.htm
*
* #return 16 random bits generated from a hardware source.
*/
unsigned int rand(); {
int i, j;
unsigned int result = 0;
/* Save state */
unsigned int TACCTL0_old = TACCTL0;
unsigned int TACTL_old = TACTL;
/* Set up timer */
TACCTL0 = CAP | CM_1 | CCIS_1; // Capture mode, positive edge
TACTL = TASSEL_2 | MC_2; // SMCLK, continuous up
/* Generate bits */
for (i = 0; i < 16; i++) {
unsigned int ones = 0;
for (j = 0; j < 5; j++) {
while (!(CCIFG & TACCTL0)); // Wait for interrupt
TACCTL0 &= ~CCIFG; // Clear interrupt
if (1 & TACCR0) // If LSb set, count it
ones++;
}
result >>= 1; // Save previous bits
if (ones >= 3) // Best out of 5
result |= 0x8000; // Set MSb
}
/* Restore state */
TACCTL0 = TACCTL0_old;
TACTL = TACTL_old;
return result;
}
/**
* Pseudo-random number generator.
*
* Implemented by a 16-bit linear congruential generator.
* NOTE: Only treat the MSB of the return value as random.
*
* #param state Previous state of the generator.
* #return Next state of the generator.
*/
unsigned int prand(unsigned int state) {
return (M * state + I); // Generate the next state of the LCG
}
This is the code for the RNG and PRNG. The list of errors:
Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) E:\Downloads\msp430-rng-master\rand.h 1
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 18
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 39
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 41
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 45
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 47
Warning[Pe012]: parsing restarts here after previous syntax error E:\Downloads\msp430-rng-master\rand.c 50
Error[Pe077]: this declaration has no storage class or type specifier E:\Downloads\msp430-rng-master\rand.c 51
Error[Pe147]: declaration is incompatible with "unsigned short volatile TA0CTL # 0x160" (declared at line 527 of "C:\Program Files (x86)\IAR Systems\Embedded E:\Downloads\msp430-rng-master\rand.c 51
Workbench 6.5\430\inc\msp430g2553.h")
Error[Be022]: location address not allowed for initialized variables (writable variables without the __no_init attribute) E:\Downloads\msp430-rng-master\rand.c 51
Error[Pe020]: identifier "TACTL_old" is undefined E:\Downloads\msp430-rng-master\rand.c 51
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 53
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\rand.c 54
Warning[Pe012]: parsing restarts here after previous syntax error E:\Downloads\msp430-rng-master\rand.c 68
The code for testing is:
#include <msp430g2553.h>
#include <signal.h>
#include <isr_compat.h>
#include "rand.h"
#define LED_OUT P1OUT
#define LED_DIR P1DIR
#define LED_RED BIT0
#define LED_GREEN BIT6
#define BLINK_DELAY 1200 // 200 ms at 6 KHz
#define BITS_RAND 16
#define BITS_PRAND 8 // Using only the MSB of the prand state
int failure = 0;
/**
* Set up the timers and blink!
*/
void prepare_to_blink() {
BCSCTL3 |= LFXT1S_2; // Set LF to VLO = 12 KHz
BCSCTL1 |= DIVA_1; // ACLK = LF / 2 = 6 KHz
TACCR0 = BLINK_DELAY; // Set the timer
TACTL = TASSEL_1 | MC_1; // TACLK = ACLK; up to CCR0
TACCTL1 = CCIE | OUTMOD_3; // TA1 interrupt enable; PWM set/reset
__bis_SR_register(LPM3_bits | GIE); // LPM3 w/ interrupt
}
int interrupt(TIMERA1_VECTOR) blink_LED (void) {
TACCTL1 &= ~CCIFG; // Unset interrupt flag
if (failure) // Toggle LEDs
LED_OUT ^= LED_RED;
else
LED_OUT ^= LED_GREEN;
}
/******************************************************************************
* Monobit
*
* SP 800-22 Rev. 1a
* http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf
******************************************************************************/
/* The hardware RNG is slow, so limit test to 400 bits. */
#define MONOBIT_TIMES_RAND 25 // 400 / BITS_RAND
/* Each 8-bit number tested with monobit contributes 8 bits, so in the worst
* case, the signed 16-bit bucket can store information about this many
* numbers: */
#define MONOBIT_TIMES_PRAND 4095 // (2 ^ 15 - 1) / BITS_PRAND
/* The maximum absolute value of the sum bucket after a monobit test, where
* 0.01 is the minimum P-value and inverfc is the inverse of the complementary
* error function. */
#define MONOBIT_MAX_VAL_RAND 51 // inverfc(0.01) * sqrt(2) * sqrt(400)
#define MONOBIT_MAX_VAL_PRAND 466 // inverfc(0.01) * sqrt(2) * sqrt(2 ^ 15 - 1)
/**
* Monobit test for rand().
*
* Returns 0 on success; otherwise otherwise.
*/
int monobit_rand() {
int sum = 0;
int i, j;
for (i = 0; i < MONOBIT_TIMES_RAND; i++) {
int r = rand();
/* Add up all the bits, taking 0 to mean -1. */
for (j = 0; j < BITS_RAND; j++) {
sum += r & 0x1 ? 1 : -1;
r >>= 1;
}
}
if (sum < 0)
sum = 0 - sum; // Absolute value
return sum > MONOBIT_MAX_VAL_RAND;
}
/**
* Monobit test for prand().
*
* Returns 0 on success; otherwise otherwise.
*/
int monobit_prand() {
int state = rand();
int sum = 0;
int i, j;
for (i = 0; i < MONOBIT_TIMES_PRAND; i++) {
int r = state >> (16 - BITS_PRAND); // Ignore the least significant bits
/* Add up all the bits, taking 0 to mean -1. */
for (j = 0; j < BITS_PRAND; j++) {
sum += r & 0x1 ? 1 : -1;
r >>= 1;
}
state = prand(state);
}
if (sum < 0)
sum = 0 - sum; // Absolute value
return sum > MONOBIT_MAX_VAL_PRAND;
}
/**
* Store the failure code on the top of the stack and alternate flashing the
* LEDs to signify failure.
*
* Never returns!
*/
void fail(int code) {
asm("push %0" : : "r" (code));
failure = 1;
LED_OUT &= ~LED_GREEN;
prepare_to_blink();
}
/**
* Run though all the tests.
*
* Both LEDs are lit up while testing, and one will blink once the tests are
* done, depending on the outcome.
*/
void main() {
LED_DIR |= LED_RED | LED_GREEN;
LED_OUT |= LED_RED | LED_GREEN;
if (monobit_rand())
fail(0xdead);
if (monobit_prand())
fail(0xbeef);
LED_OUT &= ~LED_RED;
prepare_to_blink();
}
And the list of errors when compiling:
Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) E:\Downloads\msp430-rng-master\rand.h 1
Error[Pe169]: expected a declaration E:\Downloads\msp430-rng-master\test.c 34
Warning[Pe012]: parsing restarts here after previous syntax error E:\Downloads\msp430-rng-master\test.c 116
Warning[Pe1051]: standard requires that parameter "TIMERA1_VECTOR" be given a type by a subsequent declaration ("int" assumed) E:\Downloads\msp430-rng-master\test.c 34
Error[Pe130]: expected a "{" E:\Downloads\msp430-rng-master\test.c 117
Warning[Pe940]: missing return statement at end of non-void function "interrupt" E:\Downloads\msp430-rng-master\test.c 117
Error[Pe018]: expected a ")" E:\Downloads\msp430-rng-master\test.c 126
Warning[Pe223]: function "monobit_rand" declared implicitly E:\Downloads\msp430-rng-master\test.c 144
Warning[Pe223]: function "monobit_prand" declared implicitly E:\Downloads\msp430-rng-master\test.c 147
You have incorrect syntax. Please see the following line:
unsigned int rand(); {
This line should read:
unsigned int rand() {
Edit
In your test code, you have the following:
int interrupt(TIMERA1_VECTOR) blink_LED (void) {
I have never seen an interrupt service routine defined in this way. Instead it should be defined (in IAR EW430) like this:
#pragma vector=TIMERA1_VECTOR
__interrupt void blink_LED(void) {
I am trying to get a pic16 controller to run an initialization function that displays some text on an LCD only once and then goes on to display other things
The LCD output is working fine the problem is that the initialization function keeps executing. What am I doing wrong ?
/*
* File: main.c
*
* Created on Sep 1, 2013, 12:09 PM
*/
#include <pic.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "delay.h"
__CONFIG(WDTE_ON & PWRTE_ON & MCLRE_ON & BOREN_ON & FOSC_INTRCIO );
static int exec_counter = 0;
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) // bit mask macros
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define flip_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
#define test_bit(ADDRESS,BIT) (ADDRESS & (1<<BIT))
#define E RC4 // Define the LCD Control Pins
#define RS RC5
int i; // Use Global Variables for Debug
LCDWrite(int LCDData, int RSValue)
{
PORTC = (LCDData >> 4) & 0x0F; // Get High 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the High 4 Bits Out
PORTC = LCDData & 0x0F; // Get Low 4 Bits for Output
RS = RSValue;
E = 1; E = 0; // Toggle the Low 4 Bits Out
if ((0 == (LCDData & 0xFC)) && (0 == RSValue))
DelayMs(5);
else
DelayUs(200);
} //
void writeLines(char top[],char bottom[]){
for (i = 0; top[i] != 0; i++) // Write Line 1
LCDWrite(top[i], 1);
LCDWrite(0b11000000, 0); // Move Cursor to the Second Line
for (i = 0; bottom[i] != 0; i++)// Write Line 2
LCDWrite(bottom[i], 1);
}
int countelems(char arr[]){
for (i = 0; arr[i] != 0; i++){}
return i;
}
void pad_number(char number[],char numberout[],char unit[]){
int size_n = countelems(number); // get length of number array by reference
int size_u = countelems(unit); // get length of unit array by reference
int size = size_u + size_n + 1; // calculate total size of text with 1 space between number and unit
int L_space = floor((16-size)/2)-1; // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
numberout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= (size_n); i++){
numberout[i+(L_space+1)] = number[i]; // fill output char array with number
}
numberout[L_space+size_n+1] = 0b10100000; // put space in output char array between number and unit
for (i = 0; i <= size_u; i++){
numberout[i+(L_space+size_n+2)] = unit[i]; // fill output char array with unit
}
}
void pad_text(char text[],char textout[]){
int size = countelems(text); // get length of char array by reference
int L_space = floor((16-size)/2); // calculate space required on left side of display to center text
for (i = 0; i <= 15; i++)
textout[i] = 0b10100000; // fill output char array with spaces
for (i = 0; i <= 15; i++){
if( i >= L_space && i <= (L_space+size)){
textout[i] = text[i-L_space]; // fill middle of output char array with text
}
}
}
void getAnalog(int channel,char parameter[], char unit[]){
char output_parameter[16];
char output_number[16];
char number[16];
ADCON0 = channel << 2; // select channel
//set_bit(ADCON0,7); // set ADFM flag so LSB is bit 0 of ADRESL
set_bit(ADCON0,0); // switch ADC on = set ADON flag 0b00000001
sampleTime(); // wait required aquisition time
set_bit(ADCON0,1); // start conversion = set GO/DONE bit
while(test_bit(ADCON0,1)){/* wait for ADC to complete conversion */;}
int ADCresult = (ADRESL+ADRESH)/10; // get result from ADC
itoa(number,ADCresult,10); // convert ADC result to charstring
LCDWrite(0b00000001, 0); // Clear LCD
pad_text(parameter,output_parameter);
pad_number(number,output_number,unit);
writeLines(output_parameter, output_number);
}
void init(){
DelayMs(20); // Wait for LCD to Power Up
PORTC = 3; // Start Initialization Process
E = 1; E = 0; // Send Reset Command
DelayMs(5);
E = 1; E = 0; // Repeat Reset Command
DelayUs(200);
E = 1; E = 0; // Repeat Reset Command Third Time
DelayUs(200);
PORTC = 2; // Initialize LCD 4 Bit Mode
E = 1; E = 0;
DelayUs(200);
LCDWrite(0b00101000, 0); // LCD is 4 Bit I/F, 2 Line
LCDWrite(0b00000001, 0); // Clear LCD
LCDWrite(0b00000110, 0); // Move Cursor After Each Character
LCDWrite(0b00001110, 0); // Turn On LCD and Enable Cursor
// "0123456789012345"
writeLines( " INITIALIZE ",
" TEXT ");
}
void main(void) {
OPTION_REG |= 0x7; // set prescaler to 1:128 or 2.3 Seconds
OPTION_REG |= 0x8; // assign prescaler to WDT
TRISA = 0b00000101; // configure PORTA set RA0 and RA2 to analog input;
ANSEL = 0b00000101; // disable input buffers if I/O pins RA0 and RA2
TRISC = 0; // configure PORTC as output
ADCON1 = 0; // select FOSC2
if (exec_counter == 0){
exec_counter++;
init();
DelayS(4);
}
PORTC = 0;
while (1) {
getAnalog(0,"VELOCITY","KM/H");
DelayS(4);
getAnalog(2,"ACCELERATION","M/S^2");
DelayS(4);
}
return;
}
/*
* File: delay.c
*
* Created on Sep 3, 2013, 12:09 PM
*/
#include "delay.h"
#include <pic.h>
#define _XTAL_FREQ 4000000
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char i;
do {
i = 4;
do {
DelayUs(250);
} while(--i);
} while(--cnt);
#endif
}
void DelayS(unsigned int count){
for (int i=0; i<=count;i++){
NOP();
CLRWDT();
DelayMs(1000);
}
}
void sampleTime(){
// TC = – 10pF ( 1k Ω + 7k Ω + 1k Ω ) ln(0.0004885)
// = 0.686 μS
// TACQ = 5μS + 0.686μS + [ ( 50°C- 25°C ) ( 0.05μ S /°C ) ]
// = 6.936 μS /
// 1 instruction cycle = 4μS # 1 mHz
// 1 instruction cycle = 1μS # 4 mHz
// 1 instruction cycle = 500nS # 8 mHz
// 1 instruction cycle = 200nS # 20 mHz
// TACQ # 1 mHz is 6.936 μS / 4 μS or ~ 2 instruction cycles
// TACQ # 4 mHz is 6.936 μS / 1 μS or ~ 7 instruction cycles
// TACQ # 8 mHz is 6.936 μS / 0.5 μS or ~ 14 instruction cycles
// TACQ # 20 mHz is 6.936 μS / 0.2 μS or ~ 35 instruction cycles
DelayUs(8);
}
The char number[] = ""; array is very small, yet you use it in itoa(), thus overwriting random memory.