Seven-segment display using 595 - c

I am having some trouble coding my seven-segment display using a shift register and push button. The aim is for the display to count up when the button is pressed. 0-9 then; A, B, C, D, E, and F. I did manage to get this working at first but the task was changed so the "shiftOut" command was not allowed to be used.
With my adjusted code my seven-segment display doesn't seem to be working at all now. I have tried to do a lot of my own troubleshooting (i.e. looking into debouncing, arrays, and bit-banging). Any help would be appreciated. Thanks. PS: this is my first question so sorry if the format is wrong.
/* Pins to connect to common-cathode LED display via a 74HC595:
DP-7, A-6, B-5, C-4, D-3, E-2, F-1, G-15
*/
const byte ledCharSet[128] = {
// 00-0F: Hex digits
B10000001, B11001111, B10010010, B10000110, // 0123
B11001100, B10100100, B10100000, B10001111, // 4567
B10000000, B10000100, // 89
B10001000, B11100000, B10110001, B11000010, // AbCd
B10110000, B10111000, // EF
};
//// Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//// Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
//// Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;
//// Pin connected to display's common annode
const int faderPin = 10;
int _B = 7;
bool b;
int count=0;
int value;
long time = 0;
long debounce = 500;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(_B, INPUT_PULLUP);
b = true;
toggleLatch();
toggleCLK();
Serial.begin(9600);
}
void toggleLatch() {
digitalWrite(latchPin, HIGH); digitalWrite(latchPin, OUTPUT);
}
void toggleCLK() {
digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW);
}
void loop() {
unsigned char count; // debounce counter
if (b != digitalRead(_B)) {
for(count = 0; count<20 && b != digitalRead(_B); count++);
//register the change if we have confirmed it 20 consecutive times
b=((count>=20 && b!=digitalRead(_B))?!b:b);
if(!b) {
count--;
} // button is pushed
}
toggleLatch();
void shiftBit(bool dataPin) { digitalWrite(ledCharSet,dataPin); toggleCLK(); }
void shiftByteMSF(unsigned char b) {
unsigned char b = ledCharSet[count];
unsigned char m; // use m to select the bits in b one at a time
m = 1;
for (m = B10000000; m>0; m <<= 1) {
if (b & m) {
digitalWrite(dataPin, HIGH);
} else {
digitalWrite(dataPin, LOW);
}
}
toggleLatch();
}
if (count==16) {
count=0; //reset
}
}
This is the first code I used, which worked fine.
/* Pins to connect to common-cathode LED display via a 74HC595:
DP-7, A-6, B-5, C-4, D-3, E-2, F-1, G-15 (shiftOut using MSBFIRST)
*/
const byte ledCharSet[128] = {
// 00-0F: Hex digits
B10000001, B11001111, B10010010, B10000110, // 0123
B11001100, B10100100, B10100000, B10001111, // 4567
B10000000, B10000100, // 89
B10001000, B11100000, B10110001, B11000010, // AbCd
B10110000, B10111000, // EF
};
//// Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//// Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
//// Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;
//// Pin connected to display's common annode
const int faderPin = 10;
int _B = 7;
int reading;
int previous = LOW;
int counter=0;
long time = 0;
long debounce = 500;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(_B, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
reading = digitalRead(_B);
Serial.print(counter);
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
counter++;
time = millis();
}
previous = reading;
byte bitsToSend = ledCharSet[counter];
bitsToSend = bitsToSend ^ B11111111;
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);
digitalWrite(latchPin, HIGH);
digitalWrite(11, 255);
digitalWrite(11, 0);
if (counter==16) {
counter=0; //reset count
}
}

Related

MPLAB XC8 Compiler PIC18F452 Multiplexed Seven Segment Display Code working properly

I am currently working on a code involving the MPLAB XC8 Compiler, PIC18F452 with a Multiplexed Seven Segment Display. I want to use two pushbuttons connected to pins RB2 and RB3 of PORTB of the PIC18F452 to increment and decrement a variable "count" and display this number from 0 to 99 on this display. Schematic and code is show below.
This code relatively functions as it is, and I do not believe the schematic is to blame for the issues I am seeing, nor is the byte array not correct as I am able to see each number when using the array with a 1 segment display.
The issue arrises when trying to use this multiplexing scheme shown in the below figure. I can successfully display two numbers on the seven segment displays, but there are strange anomalies present when executing this code. For one, I seem to not be able to display the number 1, 4 and occasionally 7 on either display, but when this digit does not show the display is blank, and when the button is again pushed the next number is shown as expected.
for example:
The display shows the numbers as follows for number sequences:
9... 10... 11... 12 13... 14... ect...
or
34.... 35... 36... 37....
Not sure where the issues lies, and debugging is not going well... any help would be appreciated.
Schematic for Multiplexed 7 Segment Display
#define _XTAL_FREQ 10000000
#include <xc.h>
#include <stdlib.h>
#define Digit1 PORTBbits.RB1 //variable to sink current to PNP base
#define Digit2 PORTBbits.RB2 //variable to sink current to PNP base
#define Switch1 PORTBbits.RB4 //switch decrement variable
#define Switch2 PORTBbits.RB3 //switch increment variable
#define Pressed1 1 //pressed is high
#define Pressed2 1 //pressed is high
void initialize();
void segment1 (void);
void segment2 (void);
void buttonPress(void);
void delay_ms(unsigned int);
void sendPattern1(unsigned char pattern);
void sendPattern2(unsigned char pattern3);
unsigned char rotateLeft(unsigned char pattern, int no);
unsigned char MSD, LSD, count=0;
Main code
void main(void){
initialize();
Digit1 = 0;
Digit2 = 0;
while(1){
buttonPress();
MSD = count/10 ;
segment1();
Digit2 = 1;
delay_ms(10); // Delay for 10 ms
Digit2 = 0;
LSD = count%10;
segment2();
Digit1 = 1;
delay_ms(10); // Delay for 10 ms
Digit1 = 0;
}
return;
}
Functions to index Most Significant Digit and Least Significant Digit from array to be sent to the ports to sink current low for common annode display.
void segment1(void){
unsigned char segArrayC[]={0b11000000,0b11111001,0b00100100,
0b00110000,0b00011001,0b00010010,
0b00000010,0b11111000,0b00000000,0b00011000};
unsigned char pattern;
pattern = segArrayC[MSD];
sendPattern1(pattern);
return;
}
void segment2(void){
unsigned char segArrayD[]= {0b11000000,0b11111001,0b00100100,
0b00110000,0b00011001,0b00010010,0b00000010,
0b11111000,0b00000000,0b00011000};
unsigned char pattern3;
pattern3 = segArrayD[LSD];
sendPattern2(pattern3);
return;
}
Button Press Code
void buttonPress(void){
if (Switch1 == Pressed1) {
++count;
delay_ms(100);
}
if (Switch2 == Pressed2) {
--count;
delay_ms(100);
}
if(count>=99||count<0)
{
count=0;
delay_ms(100);
}
return;
}
Function to rotate bytes in array two places to left to be displayed on PORTs
/** Rotate pattern to the left 'no' number of bits
*/
unsigned char rotateLeft(unsigned char pattern, int no) {
return (((pattern << no) & 0xFF) | (pattern >> (8-no)));
}
Functions to output indexed array char to PORTC and PORTB pins
void sendPattern1(unsigned char pattern) {
// Send pattern to appropriate port pins
unsigned char pattern2;
PORTC = pattern;
pattern2=rotateLeft(pattern, 2);
PORTB = pattern2;
return;
}
void sendPattern2(unsigned char pattern3) {
unsigned char pattern4;
PORTC = pattern3;
pattern4=rotateLeft(pattern3, 2);
PORTB = pattern4;
return;
}
Delay Function
void delay_ms(unsigned int n){
while (--n) _delay(2500);
}
Initialize pins to be used (0 output, 1 input)
void initialize() {
TRISC = 0;
TRISBbits.TRISB0 = 0;
TRISBbits.TRISB1 = 0;
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB4 = 1;
TRISBbits.TRISB3 = 1;
PORTC = 0x00;
PORTB = 0x00;
}
In sendPattern() you write a rotated bit pattern to PORTB.
This interferes with the setting the common anode control. So you see both digits only, if both right hand segments are turned on. According your schematic you should write a 0 to turn on the common anode. Try this:
void main()
{
static const unsigned char segArray[]=
{ 0b11000000, 0b11111001, 0b00100100, 0b00110000, 0b00011001,
0b00010010, 0b00000010, 0b11111000, 0b00000000, 0b00011000
};
TRISC = 0; //PortC all OUTPUT
PORTC = 0xFF; //PortC all HIGH = IDLE = LED_OFF
TRISBbits.TRISB0 = 0; //Output unused
TRISBbits.TRISB1 = 0; //Output Digit1
TRISBbits.TRISB2 = 0; //Output Digit2
TRISBbits.TRISB4 = 1; //Input: Switch PLUS
TRISBbits.TRISB3 = 1; //Input: Switch MINUS
PORTB = 0x00;
unsigned char count=0;
for(;;)
{
//Handle buttons
if (Switch1 && count<99)
{
++count;
delay_ms(100);
}
if (Switch2 && count > 0)
{
--count;
delay_ms(100);
}
//Write high digit
PORTC = segArray[count/10];
Digit2 = 0;
delay_ms(10); // Delay for 10 ms
Digit2 = 1;
//Write low digit
PORTC = segArray[count%10];
Digit1 = 0;
delay_ms(10); // Delay for 10 ms
Digit1 = 1;
}
}

AVR programming, displaying wrong value on 7 seg. LED

I am interfacing LM35 with Atmega8. To display digits I use 7 segment LED anode display that I connect to AVR both ends (it handles it without transistors so why not). Strange thing happens:
res value after assigning it from adc is 237 (23.7 degrees). I want to print on my display the first digit (2).
If I leave last line in the while commented out, the display first shows digit 2 correctly but after the first delay it shows 1 instead of 2. Otherwise I get correctly digit 2. Why is this happening?
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#define DELAY_IN_MS 500 /* 0.5 sec */
int numbers[] = {
0b01000000,
0b01110011,
0b00100100,
0b00100001,
0b00010011,
0b00001001,
0b00001000,
0b01100011,
0b00000000,
0b00000001,
0b11111111 // off
};
uint8_t digits[3];
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));
//Clear ADIF by writing one to it
ADCSRA|=(1<<ADIF);
return(ADC);
}
int main()
{
DDRD = 0xFF;
PORTD = 0xFF;
DDRB = 0b00000001;
PORTB = 1;
initADC();
uint16_t adc_value;
uint16_t res;
while(1)
{
adc_value = 0;
for (int i = 0; i < 250; i++)
{
adc_value += ReadADC(0);
}
adc_value=(adc_value/25)/4;
res = adc_value;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res /= 10;
}
uint8_t dig = digits[0];
PORTD = numbers[dig];
_delay_ms(DELAY_IN_MS);
// if following is uncommented there blinks digit two correctly
// if commented there is unblinking digit 1
PORTD = numbers[10]; // display off
}
return 0;
}
The problem was induction.
My circuit had many wires in non-soldering-field. When the display was on, there was a lot of induction going on changing resulting voltage on ADC input/LM35 output.
There is more than one solution.
1) Software: I moved ADC conversion into the interruption function. It turns of the displays, converts value from lm35 and displays digit on proper display. It happens so fast that the eye cant perceive it.
I prefer this one for now, because it makes my circuit simpler.
2) Hardware: adding L/C or R/C filter to adc pin should resolve the issue.
Full code for 1)
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define DELAY_IN_MS 5000 /* ms */
#define NUM_OF_MEASUREMENTS 100
#define NUM_DISPLAYS 3
int numbers[] = {
0b10000001,
0b10011111,
0b10100100,
0b10010100,
0b10011010,
0b11010000,
0b11000000,
0b10011101,
0b10000000,
0b10010000,
0b11111111 // off
};
int display = 0;
uint8_t digits[NUM_DISPLAYS];
volatile uint16_t adc_values[NUM_OF_MEASUREMENTS];
int adc_read_cycle_index = 0;
uint32_t res;
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while (ADCSRA & (1<<ADSC));
return(ADC);
}
void readDegrees()
{
adc_values[adc_read_cycle_index] = (ReadADC(0)*10)/4;
if(adc_read_cycle_index + 1 == NUM_OF_MEASUREMENTS) {
adc_read_cycle_index = 0;
} else {
adc_read_cycle_index++;
}
}
void fetchTemperatureDigits() {
res = 0;
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
res += adc_values[i];
}
res /= NUM_OF_MEASUREMENTS;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res = res / 10;
}
}
void initTimer0()
{
// Prescaler = FCPU/64
TCCR0|=(1<<CS01);//|(1<<CS00);
//Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
//Initialize Counter
TCNT0=0;
}
ISR(TIMER0_OVF_vect)
{
// turn off displays
PORTD = numbers[10];
// read ADC and convert to degrees
readDegrees();
// turn on proper anode
PORTB &= 0b11111000;
PORTB |= (1<<display);
// show digit
PORTD = numbers[digits[display]];
// show decimal point for second display (21.5 - second display shows "1.")
if(display == 1) {
PORTD &= 0b01111111;
}
// next display for next interruption
display++;
if(display == NUM_DISPLAYS) {
display = 0;
}
}
int main()
{
initADC();
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
readDegrees();
}
DDRD = 0xFF;
PORTD = 0;
DDRB |= 0b00000111;
PORTB |= 1;
initTimer0();
sei();
while(1) {
fetchTemperatureDigits();
_delay_ms(DELAY_IN_MS);
}
return 0;
}

Modify ALSA arecord function to output audio levels to Raspberry Pi 3 RGB LED

I currently can use my raspberry pi 3 to redirect USB Audio input to an icecast stream. Currently it works fine in small tests when I pipe arecord from USB audio hw input to avconv (ffmpeg equivalent) on Raspbian Jessie Lite.
Arecord has a built in text vu meter for audio levels when you use the verbose setting.
I think the code is located in the attached function. I'm wondering if it's possible to rewrite this function to output to Raspberry Pi 3 RGB LED - to somehow send the red/yellow/green based on volume levels - using the function's peak variable?
I've include the whole function - and the print function. If it could be done, I think the code could probably replace print_vu_meter(perc, maxperc);
Is it possible to modify arecord to get the Raspi 3 to handle the processing during the pipe? Is there a way to use another thread?
Way out of my league here - just looking for a start, or some ideas to get the idea out of my head or to say it's possible.
peak handler
static void compute_max_peak(u_char *data, size_t count)
{
signed int val, max, perc[2], max_peak[2];
static int run = 0;
size_t ocount = count;
int format_little_endian = snd_pcm_format_little_endian(hwparams.format);
int ichans, c;
if (vumeter == VUMETER_STEREO)
ichans = 2;
else
ichans = 1;
memset(max_peak, 0, sizeof(max_peak));
switch (bits_per_sample) {
case 8: {
signed char *valp = (signed char *)data;
signed char mask = snd_pcm_format_silence(hwparams.format);
c = 0;
while (count-- > 0) {
val = *valp++ ^ mask;
val = abs(val);
if (max_peak[c] < val)
max_peak[c] = val;
if (vumeter == VUMETER_STEREO)
c = !c;
}
break;
}
case 16: {
signed short *valp = (signed short *)data;
signed short mask = snd_pcm_format_silence_16(hwparams.format);
signed short sval;
count /= 2;
c = 0;
while (count-- > 0) {
if (format_little_endian)
sval = __le16_to_cpu(*valp);
else
sval = __be16_to_cpu(*valp);
sval = abs(sval) ^ mask;
if (max_peak[c] < sval)
max_peak[c] = sval;
valp++;
if (vumeter == VUMETER_STEREO)
c = !c;
}
break;
}
case 24: {
unsigned char *valp = data;
signed int mask = snd_pcm_format_silence_32(hwparams.format);
count /= 3;
c = 0;
while (count-- > 0) {
if (format_little_endian) {
val = valp[0] | (valp[1]<<8) | (valp[2]<<16);
} else {
val = (valp[0]<<16) | (valp[1]<<8) | valp[2];
}
/* Correct signed bit in 32-bit value */
if (val & (1<<(bits_per_sample-1))) {
val |= 0xff<<24; /* Negate upper bits too */
}
val = abs(val) ^ mask;
if (max_peak[c] < val)
max_peak[c] = val;
valp += 3;
if (vumeter == VUMETER_STEREO)
c = !c;
}
break;
}
case 32: {
signed int *valp = (signed int *)data;
signed int mask = snd_pcm_format_silence_32(hwparams.format);
count /= 4;
c = 0;
while (count-- > 0) {
if (format_little_endian)
val = __le32_to_cpu(*valp);
else
val = __be32_to_cpu(*valp);
val = abs(val) ^ mask;
if (max_peak[c] < val)
max_peak[c] = val;
valp++;
if (vumeter == VUMETER_STEREO)
c = !c;
}
break;
}
default:
if (run == 0) {
fprintf(stderr, _("Unsupported bit size %d.\n"), (int)bits_per_sample);
run = 1;
}
return;
}
max = 1 << (bits_per_sample-1);
if (max <= 0)
max = 0x7fffffff;
for (c = 0; c < ichans; c++) {
if (bits_per_sample > 16)
perc[c] = max_peak[c] / (max / 100);
else
perc[c] = max_peak[c] * 100 / max;
}
if (interleaved && verbose <= 2) {
static int maxperc[2];
static time_t t=0;
const time_t tt=time(NULL);
if(tt>t) {
t=tt;
maxperc[0] = 0;
maxperc[1] = 0;
}
for (c = 0; c < ichans; c++)
if (perc[c] > maxperc[c])
maxperc[c] = perc[c];
putchar('\r');
print_vu_meter(perc, maxperc);
fflush(stdout);
}
else if(verbose==3) {
printf(_("Max peak (%li samples): 0x%08x "), (long)ocount, max_peak[0]);
for (val = 0; val < 20; val++)
if (val <= perc[0] / 5)
putchar('#');
else
putchar(' ');
printf(" %i%%\n", perc[0]);
fflush(stdout);
}
}
print_vu_meter
static void print_vu_meter_mono(int perc, int maxperc)
{
const int bar_length = 50;
char line[80];
int val;
for (val = 0; val <= perc * bar_length / 100 && val < bar_length; val++)
line[val] = '#';
for (; val <= maxperc * bar_length / 100 && val < bar_length; val++)
line[val] = ' ';
line[val] = '+';
for (++val; val <= bar_length; val++)
line[val] = ' ';
if (maxperc > 99)
sprintf(line + val, "| MAX");
else
sprintf(line + val, "| %02i%%", maxperc);
fputs(line, stdout);
if (perc > 100)
printf(_(" !clip "));
}
Doesn't look like there's much interest in this, but I thought I'd post my answer for future, in case anyone else tries to delve into this type of project.
Findings:
arecord is just a linked copy of aplay
you can use the incredible wiringPi c library to add a thread to the C code
by adding a static volatile int variable to the code - it becomes shared with between thread and main program
setting the variable to the perc value means it's updated immediately in the threaded program
I was able to simulate a 6 level audio level meter with LEDs using this code:
I used a button on the breadboard to toggle between LED levels being displayed and not.
setAudioLEDS threaded function:
PI_THREAD (setAudioLEDs)
{
// Only update LEDS if button is pressed
// Gets Audio Level from global var: globalAudioLevel
// Wiring Pi Constants for led and button
// Pin number declarations. We're using the Broadcom chip pin numbers.
#define CYCLE_UPDATE '0'
#define CYCLE_STEADY '1'
int last_button;
int last_cycle;
int this_cycle;
// Button is released if this returns 1
// HIGH or LOW (1 or 0)
last_button = digitalRead(butPin);
last_cycle = CYCLE_STEADY;
this_cycle = last_cycle;
while (1)
{
if (digitalRead(butPin) != last_button) {
if (last_cycle == CYCLE_UPDATE)
this_cycle = CYCLE_STEADY;
else
this_cycle = CYCLE_UPDATE;
last_cycle = this_cycle;
}
switch (this_cycle) {
case CYCLE_UPDATE:
// Set LEDS based on audio level
if (globalAudioLevel > 20)
digitalWrite(led1, HIGH); // Turn LED ON
else
digitalWrite(led1, LOW); // Turn LED OFF
if (globalAudioLevel > 40)
digitalWrite(led2, HIGH); // Turn LED ON
else
digitalWrite(led2, LOW); // Turn LED OFF
if (globalAudioLevel > 60)
digitalWrite(led3, HIGH); // Turn LED ON
else
digitalWrite(led3, LOW); // Turn LED OFF
if (globalAudioLevel > 70)
digitalWrite(led4, HIGH); // Turn LED ON
else
digitalWrite(led4, LOW); // Turn LED OFF
if (globalAudioLevel > 80)
digitalWrite(led5, HIGH); // Turn LED ON
else
digitalWrite(led5, LOW); // Turn LED OFF
if (globalAudioLevel > 90)
digitalWrite(led6, HIGH); // Turn LED ON
else
digitalWrite(led6, LOW); // Turn LED OFF
break;
default:
/* Button hasn't been pressed */
digitalWrite(led1, LOW); // Turn LED OFF
digitalWrite(led2, LOW); // Turn LED OFF
digitalWrite(led3, LOW); // Turn LED OFF
digitalWrite(led4, LOW); // Turn LED OFF
digitalWrite(led5, LOW); // Turn LED OFF
digitalWrite(led6, LOW); // Turn LED OFF
}
}
}
I have something working as a ALSA scope plugin so any audio played will start my led vu meter. All you have to do is install the plugin and edit /etc/asound.conf to include the plugin.
I found pivumeter (https://github.com/pimoroni/pivumeter) which is based on ameter (http://laugeo.free.fr/ameter.html) and created my own devices for a 2 channel stereo 16 LED using GPIO pins and another that uses two shift registers and SPI.
My fork can be found here: https://github.com/linuxgnuru/pivumeter
To add your own device, you'll need to edit Makefile.am, src/pivumeter.c (at the bottom add your function), src/devices/all.h, and your code in src/devices/YOURDEVICE.c and src/devices/YOURDEVICE.h
I plan on going through the ALSA C library for the scope plugin and making my own plugin from scratch.
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___scope.html

Input capture value is double in atmea128

I am learning embedded C with Atmega128 and Atmel Studio.
I want to write code that shows the temperature and humidity from a sensor.
I am learning Input Capture and my first question is:
I get IC with value 5000(period) but I think 2500 is correct. Am I calculating it right? If so, do you have any idea why IC has the wrong value?
16000.000/64 = 250000
1 second 250000 puls
100 ms x = 2500
Board info:
avr128
16.000.000 external clock.
philips puls generator info:
Repitation 100 mili s
Duration 10 ms
5 volt
My code
volatile uint32_t iccnt=0,ovfcnt=0;
volatile uint32_t myCapt [2],lastCapt;
//__________________________
void initTimer()
{
TCNT1 =0;//Max=65535
TCCR1B |= 1<<CS10 | 1<<CS11 ;
// 1<<CS10 | 1<<CS11 ;//16000000/16=250000
//250000/65535=3.81
//TCCR1B |= 1<<WGM13 |1<<WGM12;
TIMSK |= 1<<TOIE1;
TIFR = 1<<TOV1;
sei();
}
void initInputCapture()
{
// First Capture on rising edge
TCCR1B |=1<<ICES1;
//ic intrrupt flag enable
TIMSK |= 1<< TICIE1;
// set input pin to get signal
}
void initlcd()
{
lcd_init(LCD_DISP_ON_CURSOR_BLINK);
lcd_clrscr();
}
void ShowA(unsigned int a)
{
char aa[11];
if (a >32000) {
itoa(a - 32000,aa,10);
lcd_puts("32000+");
lcd_puts(aa);
} else {
itoa(a,aa,10);
lcd_puts(aa);
}
}
ISR(TIMER1_OVF_vect)
{
ovfcnt++;
}
ISR(TIMER1_CAPT_vect)
{
iccnt++;
myCapt[iccnt % 2] = ICR1 - lastCapt;
lastCapt = ICR1;
}
void ShowCaptureTime2()
{
lcd_clrscr();
ShowA (iccnt);
lcd_puts(": \n");
ShowA(myCapt[(iccnt - 1) % 2]);
for (int j=0;j<(1000) ;j++)
{
for (int i=0;i<4000;i++)
{
}
}
}
//*******************************
//*******************************
int main(void)
{
DDRG = 0b11111111;
int cnt = 0;
initlcd();
initTimer();
initInputCapture();
while(1)
{
ShowCaptureTime2();
}
}
I could find the answer yesterday. code has no problem. Pulse generator work not correktly! incorrect input!!!! – samsoft

Why doesn't the LED turn off?

I have a program (copied below) that has an alarm that starts in 10 seconds, which starts a LED that blinks every two seconds. I would like to push a button that turns off the alarm / LED. The LED blinks as intended but does not turn off when I push the button. Any idea why? Code below:
#include <Time.h>
#include <TimeAlarms.h>
#define buttonPin 2 // assigns pin 2 as buttonPin
#define ledPin 13 // assigns pin 13 as ledPin
int buttonState; // variable for reading the pushbutton status
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
Serial.begin(9600); // start Serial Monitor
setTime(0, 0, 0, 1, 1, 2018); // set time to 00:00:00 Jan 1 2018
Alarm.alarmRepeat(0, 0, 10, DailyAlarm); // Alarm triggered in 10 sec
pinMode(ledPin, OUTPUT); // assigns ledPin as led output pin.
pinMode(buttonPin, INPUT); // assigns buttonPin as input pin
// digitalWrite(ledPin, ledState); // LED is off initially
}
void loop() {
digitalClockDisplay();
Alarm.delay(1000); // wait one second between clock display
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = HIGH;
Serial.print(buttonState);
}
}
}
void DailyAlarm() {
Serial.println("Alarm");
while (buttonState == LOW) {
blink(2000); // blink every 2s
}
}
void blink(int period) {
digitalWrite(ledPin, HIGH);
delay(period / 2);
digitalWrite(ledPin, LOW);
delay(period / 2);
}
void digitalClockDisplay() {
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.println();
}
void printDigits(int digits) {
Serial.print(":");
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
int buttonState; // variable for reading the pushbutton status
You haven't initialized the button state
Try
boolean buttonState = LOW
And Don't mix integers and booleans
use this
boolean lastButtonState = LOW;
instead of
int lastButtonState = LOW;

Resources