synthesizer - recording pressed keypad - c

I have to build synthesizer and I am using C for programing my ATmega128A. I need to record the keypads pressed and play them after some time. For keypad press I am using polling in the main.c. For playing the keypads I am using Timer1. Every time when the timer expires I am storing the keypad frequency and increment counter for it. During play, I calculate the duration firstle, then play it for that interval. When I want to play the stored song, it ticks for some time and starts to make a long sound.
Also, I want to make possible to press, record and palay simultanous keypads. Can you suggest some algorithm for this?
main.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include "keypad.h"
unsigned char temp; // to get keyboard input to play a note
unsigned char option; //to choose the embedded music to play
#define DELAY 1000
int main(void)
{
DDRG = 0xff; // To send sound to BUZ speakers (BUZ is connected to PG.4)
DDRD = 0x00; // Make it input, to get corresponding key to play a note
PORTD = 0xff; // All bits are 1s, so no button is pressed in the beginning
sei(); //Set Interrupt flag as enabled in SREG register
option = no_music; //No music is played on startup, this is default mode for free playing
// This loop keeps playing forever, so the main functionality
// of the program is below
DDRB = 0xff;
DDRD = 0x00; //ready for input
while(1)
{
temp = PIND; //store keyboard input for temporary variable
//PORTB = PIND;
switch(temp)
{
case 254: { // if 1st pin of PORTD is pressed
play_note(notes5[0]); // play corresponding note from octave 5 for 200ms
break;
}
case 253: { // if 2nd pin of PORTD is pressed
play_note(notes5[1]);
break;
}
case 251: { // if 3rd pin of PORTD is pressed
play_note(notes5[2]);
break;
}
case 247: { // if 4th pin of PORTD is pressed
play_note(notes5[3]);
break;
}
case 239: { // if 5th pin of PORTD is pressed
play_note(notes5[4]);
break;
}
case 223: { // if 6th pin of PORTD is pressed
play_note(notes5[5]);
break;
}
case 191: { // if 7th pin of PORTD is pressed
play_note(notes5[6]);
break;
}
case 127: {
if(isRecordingEnabled){
disableRecording();
//toggling LED as the sign of playing the record
toggleLED();
custom_delay_ms(DELAY);
toggleLED();
custom_delay_ms(DELAY);
custom_delay_ms(DELAY);
play_record();
}else{
//toggling LED as the sign of record start
toggleLED();
enableRecording();
}
}
}
}
return 0;
}
keypad.c
#include "structs.h"
#include "play.h"
#define F_CPU 16000000UL // 16 MHz
#include <util/delay.h>
#define BUFFER_SIZE 100
struct played_note buffer[BUFFER_SIZE];
int i = 0;
int8_t isRecordingEnabled = 0;
int8_t recordIndex = 0;
int8_t pressedNote;
int8_t isPressed = 0;
int8_t isPlaying = 0;
unsigned int ms_count = 0;
#define INTERVAL 100
#define DELAY_VALUE 0xFF
ISR(TIMER1_COMPA_vect){
// every time when timer0 reaches corresponding frequency,
// invert the output signal for BUZ, so it creates reflection, which leads to sound generation
//check whether the key was pressed because
//when the recording is enabled the interrupt is working make sound
if(isPressed || isPlaying)
PORTG = ~(PORTG);
if(isRecordingEnabled){
if(PIND == DELAY_VALUE)
pressedNote = DELAY_VALUE;
if(i == 0){
buffer[i].note = pressedNote;
buffer[i].counter = 0;
i++;
}else{
if(buffer[i - 1].note == pressedNote){
//the same note is being pressed
buffer[i - 1].counter++;
}else{
buffer[i++].note = pressedNote;
buffer[i].counter = 0;
}
}
}
}
void initTimer1(){
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256
}
void stopTimer1(){
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
}
void enableRecording(){
isRecordingEnabled = 1;
i = 0;
ms_count = 0;
initTimer1();
}
void disableRecording(){
isRecordingEnabled = 0;
stopTimer1();
}
//Timer1A
void play_note_during(unsigned int note, unsigned int duration){
OCR1A = note;
pressedNote = note;
isPressed = 1;
initTimer1();
custom_delay_ms(duration);
stopTimer1();
isPressed = 0;
}
//Timer1A
void play_note(unsigned int note){
play_note_during(note, INTERVAL);
}
void play_record(){
isPlaying = 1;
recordIndex = 0;
int duration;
while(recordIndex < i){
PORTB = buffer[return].counter << 8;
duration = INTERVAL * buffer[recordIndex].counter;
if(buffer[recordIndex].note == DELAY_VALUE)
custom_delay_ms(duration);
else
play_note_during(buffer[recordIndex].note, duration);
recordIndex++;
}
isPlaying = 0;
}
Further references can be found in the following github repository:
https://github.com/bedilbek/music_simulation

Actually your question about how to record and replay key presses, should be anticipated by another question about how to play several sounds simultaneously.
Now you're using just PWM output with variable frequency. But this allows you to generate only a single wave of a square form. You cannot play two notes (except of using another timer and another PWM output).
Instead of that, I suggest you to use PWM at the highest frequency and apply a RC or LC filters to smooth high-frequency PWM signal into a waveform, and then apply that waveform to the amplifier and to the speaker to make a sound.
Having this approach you make generate different waveforms, mix them together, make them louder or more silent and even apply a "fade-out" effect to make them sound like a piano.
But your question is not about how to generate that kind of wave-forms, so if you want to know you should start another question.
So, returning to your question.
Instead of having single procedure, which is starting note, holding a pause and only then returning back; I suggest you to have a several procedures, one play_note(note) - which will start playing a note and returns immediately (while note continue playing). And, of course, stop_note(note) - which will stop specified note, if it is played. Also I suggest you to pass a note number, rather than frequency or timer period to the play function. Let's assume 0 is the lowest possible note (e.g. C2), and then they go sequentially by semitones: 1 - C#2, 2 - D2, .... 11 - B2, 12 - C3 ... etc.
For the first time, you may remake your single-note playing procedures to match that.
// #include <avr/pgmspace.h> to store tables in the flash memory
PROGMEM uint16_t const note_ocr_table[] = {
OCR1A_VALUE_FOR_C2, OCR1A_VALUE_FOR_C2_SHARP, ... etc
}; // a table to map note number into OCR1A value
#define NOTE_NONE 0xFF
static uint8_t current_note = NOTE_NONE;
void play_note(uint8_t note) {
if (note >= (sizeof(note_ocr_table) / sizeof(note_ocr_table[0])) return; // do nothing on the wrong parameter;
uint16_t ocr1a_val = pgm_read_word(&note_ocr_table[note]);
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled // why you need this? May be you want to use just inverting OC1A output?
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256 // you may want to use lesser prescalers and higher OCR1A values ?
OCR1A = ocr1a_val;
if (TCNT1 >= ocr1a_val) TCNT1 = 0; // do not miss the compare match when ORC1A is changed to lower values;
current_note = note;
}
void stop_note(uint8_t note) {
if (note == current_note) { // ignore stop for non-current note.
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
current_note = NOTE_NONE; // No note is playing
}
}
so, now your task is very simple: you should just pull the state of the keys periodically, let's say 61 times per second (based on the some 8-bit timer with 1:1024 prescaler overflow), and they to note: which keys are changed their state. If some key is pressed, you call play_note to start coressponding note. If the key is released, you call stop_note, also you're counting how many timer cycles passed since the last event.
When recording, you just push those events into array "key X is pressed" or "key X is released" or "X timer cycles expired".
When playing back, you just performing a backward process, scaning your array, and executing commands: calling play_note, stop_note, or waiting exact amount of timer cycles, if it is a pause.
Instead of writing giant switch statement, you may also use a table to scan the buttons
// number of element in the port-state arrays
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define F 5
typedef struct {
port_index uint8_t;
mask uint8_t;
} KeyLocation;
PROGMEM KeyLocation const key_location[] = {
{ B, (1 << 1) }, // where C2 is located, e.g. PB1
{ E, (1 << 3) }, // where C#2 is located, e.g. PE3
...
}
uint16_t ticks_from_prev_event = 0;
uint8_t port_state_prev[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0XFF};
for (;;) { // main loop
wait_tick_timer_to_overflow();
// latching state of the pins
uint8_t port_state[6] = {PINA, PINB, PINC, PIND, PINE, PINF};
for (uint8_t i = 0 ; i < (sizeof(key_location) / sizeof(key_location[0])) ; i++) {
uint8_t port_idx = pgm_read_byte(&key_location[i].port_index);
uint8_t mask = pgm_read_byte(&key_location[i].mask);
if ((port_state[port_idx] & mask) != (port_state_prev[port_idx] & mask)) { // if pin state was changed
if (is_recording && (ticks_from_prev_event > 0)) {
put_into_record_pause(ticks_from_prev_event); // implement it on your own
}
if ((port_state[port_idx] & mask) == 0) { // key is pressed
play_note(i);
if (is_recording) {
put_into_record_play_note(i); // implement
}
} else { // key is released
stop_note(i);
if (is_recording) {
put_into_record_stop_note(i); // implement
}
}
}
}
// the current state of the pins now becomes a previous
for (uint8_t i = 0 ; i < (sizeof(port_state) / sizeof(port_state[0])) ; i++) {
port_state_prev[i] = port_state[i];
}
if (ticks_from_prev_event < 65535) ticks_from_prev_event++;
}
put_into_record_... implement as you wish.
the playback would be the same simple (below just the template, you'll suggest from the function name what they should do)
while (has_more_data_in_the_recording()) {
if (next_is_play()) {
play_note(get_note_from_recording())
} else if (next_is_stop()) {
play_note(get_note_from_recording())
} else {
uint16_t pause = get_pause_value_from_recording();
while (pause > 0) {
pause--;
wait_tick_timer_to_overflow();
}
}
}
This approach gives you two benefits:
1) It doesn't matter how many notes the playing module can play, the keys are recorder while they are pressed and released, so, all simultaneous keys will be recorded and replayed in the same time.
2) It doesn't matter how many notes are pressed in exact the same moment. Since pause and key events are recorded separately, during the replay all the same-time key presses will be replayed in the same time, without an "arpeggio" effect

Related

time between two edges pic 18f4550

I would like to calculate the time interval between two rising edges of two different signals using the two CCP modules from pic 18f4550.
The idea of ​​calculation is illustrated in the following figures.
The simulation works fine, but my electrical circuit is not. I don't know if there is something wrong with my code. If anyone has an answer or a clue to fix this, I will be grateful! And if you have any questions, please feel free to ask.
#pragma config FOSC = INTOSC_EC
#define _XTAL_FREQ 8000000
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage, capt0, x;
char DEPHASAGE[20];
char pulse[20];
float period, dephTempo, deph, phi;
void main()
{
IRCF0 = 1; /* set internal clock to 8MHz */
IRCF1 = 1;
IRCF2 = 1;
LCD_Init();
LCD_String_xy(0, 1, "Dephasage[rad]");
T3CONbits.RD16 = 1;
T3CKPS0 = 0;
T3CKPS1 = 0;
TMR3CS = 0;
TMR3IF = 0;
while (1)
{
CCP2CON = 0b00000101;
CCP1CON = 0b00000101;
PIR2bits.CCP2IF = 0;
PIR1bits.CCP1IF = 0;
TMR3ON = 0;
TMR3 = 0;
if (PIR1bits.CCP1IF == 1) {
TMR3ON = 1;
while (!PIR2bits.CCP2IF);
comtage = TMR3;
dephTempo = (((float)comtage / 30.518) / 65536);
sprintf(pulse,"%.3f ", dephTempo);
LCD_String_xy(0, 0, "Dephasage : ");
LCD_String_xy(2, 9, pulse);
}
}
}
When you test a schematic using a real circuit, other issues will appear, like capacitive and resistive parasitics and that will after the timings. Also, can have jitter noise. If you a have an oscilloscope, try to figure out if there is too much noise. Try do add a pull-down/pull-up on those lines, make sure you have good ground connection. But after looking for your code, you should take an approach similar to CTC: You make fast samples of your input signal and then you check your sampled array, if there is more one than zeros, you caught an edge trigger.
I have a better scenario for your application to implement. But first let's talk about the bad practices in your code.
In your main while loop you setup the CCP modules:
CCP2CON = 0b00000101;
CCP1CON = 0b00000101;
PIR2bits.CCP2IF = 0;
PIR1bits.CCP1IF = 0;
TMR3ON = 0;
TMR3 = 0;
You better do this before the program enters to the infinite while loop.
You handle the timer reads directly while the CCP module captures its value in which the edge you configured it to capture.
comtage = TMR3;
I don't see that you configure the CCP pins as inputs. You have to configure them as inputs by setting the corresponding TRIS bits in order to have them working properly.
So the structure of my recommended scenario would be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "LCD_8bit_file.h"
#include <string.h>
unsigned long comtage, capt0, x;
char DEPHASAGE[20];
char pulse[20];
float period, dephTempo, deph, phi;
/******************** Utility funcs ********************/
void setupSysClock() {
IRCF0 = 1; /* set internal clock to 8MHz */
IRCF1 = 1;
IRCF2 = 1;
}
void setupCCP1withTMR1() {
CCP1CON = 0b00000101;
PIR1bits.CCP1IF = 0;
TRISCbits.TRISC2 = 1; // set CCP1 pin as input
}
void setupCCP2withTMR3() {
CCP2CON = 0b00000101;
PIR2bits.CCP2IF = 0;
// T3 goes for CCP2 and CCP1, PS 1:1, internal CS
T3CON = (1 << T3CCP2) | (0 << T3CKPS1) | (0 << T3CKPS0) | (1 << T3CCP1) | (0 << TMR3CS);
TMR3 = 0;
// In config bits you must choose RC1 pin for the CCP2 if necessary although it so by default
TRISCbits.TRISC1 = 1 // set CCP2 pin as input
}
void rearm() {
CCP1CON = 0x5
CCP2CON = 0x5
PIR1bits.CCP1IF = 0;
PIR2bits.CCP2IF = 0;
TMR3 = 0;
TMR3ON = 1;
}
void suspend() {
CCP1CON = 0;
CCP2CON = 0;
}
void main()
{
setupSysClock(); // setu internal clock
setupCCP1withTMR1(); // setup CCP1 for capture mode
setupCCP2withTMR3(); // setup CCP1 for capture mode with TMR3
LCD_Init();
LCD_String_xy(0, 1, "Dephasage[rad]");
while (1)
{
while(!CCP2IF); // Wait for the second rising edge
// Event has occured process, first make sure that the CCP1 rised first
if(!CCP1F) {
// An invalid sequence occured ignore and rearm. Note that the sequence of signals is important.
rearm();
continue;
}
/* The sequence is correct let's process the event. Here you will have
two captured value in CCPR1 and CCPR2 registers. First one is the captured value of the T3 when the first rising event occured. Second one is the captured value of the T3 when the second rising event occured. You have to get the delta of the two captured values first. This delta value is the elapsed ticks between the two discrete rising input signals. This is what the capture hardware is made for ;)
Now first we shuld suspend the CCP modules to avoid unwanted captures
while we process the previous value. Because if another capture occures
before we process the previous value, the new capture value will be
overwritten over the old value that we need for computation.
*/
suspend(); // suspend the CCP modules while processing
uint16_t timeDelta = CCPR2 - CCPR1; // Calculate the difference
dephTempo = (((float)timeDelta / 30.518) / 65536);
sprintf(pulse,"%.3f ", dephTempo);
LCD_String_xy(0, 0, "Dephasage : ");
LCD_String_xy(2, 9, pulse);
// Now that we finished processing we can rearm the CCP for new captures
rearm();
}
}
I wrote this code in an editor and haven't compiled in MPLAB. So you must compile and test the code. You can give me a feedback for me to help further.
One important thing to note: If the amount of time between two signals is large, you must either increment the prescaler of Timer3 or you must use a complementary variable for TMR3 register in case it overflows.

No output for Embedded application with PIC12, MPLAB and UART

I am working on RGB LED project and that's controlled by a PIC12F1572. The software that I am using is MPLAB IDE with the HiTech C compiler. The plan is to use serial communication to send LED RGB combination data commands to the PIC to be stored in a variable that will make it perform the LED blink and glowing I have been able to establish UART communication.Every function or step I code is right by syntax and works on linux command line terminal if I compile..
And it fails if I try to simulate using register injection in MPLAB.I wanted to run it in simulation also (anyone knows how register injection actuallly works in MPLAB?)
The problem I face together when I try to debug . it compiles but doesn't work
here is my code :
Any idea or hint about the problem will be highly appreciated.
I personally fee that placing the code [hierarchical way] may be wrong
Thanks!
#include <xc.h>
#include "mcc.h"
#include "LED.h"
#include "tmr0.h"
#include "interrupt_manager.h"
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color);
void main(void)
{
uint8_t data, i, j;
uint16_t R_value, G_value, B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE] ,RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
// EUSART_Write(0x61);
while (!RCIF)
{
data = EUSART_Read(); // Read received character
for (i = 0; i < FRAMESIZE; i++)
{
RX_Buffer[i] = data;
}
EUSART_Write(data);
}
//check if any data is received
for (j = 0; j = 5; j++) // get the RGB value in the separate array
{
RGB_data[j] = RX_Buffer[j + 3];
HEX_data[value] = RGB_data[j] / 16;
}
if (RX_Buffer[0] == 'R' && RX_Buffer[FRAMESIZE - 1] == '\n')
{
//ASCII to HEX separate values
// uint32_t number = (uint32_t)strtol(HEX_data, NULL, 16);
// R_value = number >>16;
// G_value = (number & 0xffff) >> 8;
// B_value = (number & 0x0000FF);
R_value = (uint16_t) atoh(HEX_data[0], HEX_data[1]);
G_value = (uint16_t) atoh(HEX_data[2], HEX_data[3]);
B_value = (uint16_t) atoh(HEX_data[4], HEX_data[5]);
}
SetLedColor(R_value, G_value, B_value);
}
}
void SetLedColor(uint16_t R_color, uint16_t G_color, uint16_t B_color)
{
if (R_color == 0xFF)
{
LATAbits.LATA2 = 1;
}
else
{
LATAbits.LATA2 = 0;
}
if (G_color == 0xFF)
{
LATAbits.LATA4 = 1;
}
else
{
LATAbits.LATA4 = 0;
}
if (B_color == 0xFF)
{
LATAbits.LATA5 = 1;
}
else
{
LATAbits.LATA5 = 0;
}
}
So till the receiving the UART frame and echoed back and from the storing data make LED blink , I am able to succeed and this is what I wanted for primary step here by hierarchical way
#include "mcc_generated_files/mcc.h"
#include <stdlib.h>
#include <stdio.h>
#include "atoh.h"
#include "LED.h"
#define _XTAL_FREQ 16000000
#define FRAMESIZE 19
void main(void)
{
uint8_t data,i,j,got_char;
uint8_t R_value, G_value ,B_value;
uint8_t value;
uint8_t RX_Buffer[FRAMESIZE];
uint8_t RGB_data[6] ,HEX_data[6];
// initialize the device
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts
INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts
while (1)
{
if (EUSART_DataReady)
{
for (i = 0; i<FRAMESIZE; i++)
{
RX_Buffer[i] = EUSART_Read();
if (RX_Buffer[i] == '\n')
break;
}
RX_Buffer[i] = '\n'; //append '\n' at the end of stoaring array for detection of frame
RX_Buffer[i+1] = '\0'; // End of an array
EUSART_WriteAnArrayOfBytes(RX_Buffer);
if(RX_Buffer[0]=='R' && RX_Buffer[FRAMESIZE-2] == '\n') //check for correct frame
{
LATAbits.LATA2 = 1;
__delay_ms(2000);
LATAbits.LATA2 = 0;
__delay_ms(1000);
}
}
}

arduino `shiftOut()` function in native c

I'm trying to create the equivalent of the arduino shiftOut() function in native c on my mcu.
I want to send the command int gTempCmd = 0b00000011; via a shiftOut() type function with MSBFIRST.
What would the pseudo code for this look like so I can try map it my mcu's gpio functions?
Thanks
float readTemperatureRaw()
{
int val;
// Command to send to the SHT1x to request Temperature
int gTempCmd = 0b00000011;
sendCommandSHT(gTempCmd);
...
return (val);
}
//Send Command to sensor
void sendCommandSHT(int command)
{
int ack;
shiftOut(dataPin, clockPin, MSBFIRST, command);
....
}
Consider the following 'psuedo-c++'
The code works as follows:
take the highest, or lowest bit in the word by AND-ing with all zero's except the MSB or LSB, depending on the MSBFIRST flag
write it to the output pin
shift the command one step in the right direction
pulse the clock pin
repeat 8 times, for each bit in the command
It is fairly trivial to expand this to an arbitrary number of bits upto 32 by adding a parameter for the number of repetitions
void shiftOut(GPIO dataPin, GPIO clockPin, bool MSBFIRST, uint8_t command)
{
for (int i = 0; i < 8; i++)
{
bool output = false;
if (MSBFIRST)
{
output = command & 0b10000000;
command = command << 1;
}
else
{
output = command & 0b00000001;
command = command >> 1;
}
writePin(dataPin, output);
writePin(clockPin, true);
sleep(1)
writePin(clockPin, false);
sleep(1)
}
}

I am struggling to understand this code [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I spent more time and struggling to understand this code.
I edited and manage to display the data on LCD but
I would like to understand it.
I have added some comment to the code to show my bit understanding.
// Control 16 character LCD (2x8 chars) with 4 bit interface
// Copyright (C) 2012 Joonas Pihlajamaa. Released to public domain.
// No warranties, use at your own responsibility.
#include <avr/io.h>
#define F_CPU 12000000UL // 12 MHz
#include <util/delay.h>
#define DATA_PORT_DIR DDRB // macro for data port direction
#define DATA_PORT PORTB //macro for data port
#define DATA_PORT_IN PINB //macro for data port pin
#define RW_PIN (1<<PD4) // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5) // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6) // PORTD Pin6 is defined as for EN
// macro or something else? confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)
// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
if(DATA_PORT_DIR != 0xFF) // condition to test if DATA_PORT_DIR is true
//make DATA_PORT_DIR as output to write data to ldc
DATA_PORT_DIR = 0xFF;
CLEAR_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
DATA_PORT = data;
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
CLEAR_CTRL_BIT(EN_PIN);
}
unsigned char lcd_read(char rs)
{
unsigned char data;
if(DATA_PORT_DIR != 0)
DATA_PORT_DIR = 0;
SET_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
data = DATA_PORT_IN;
CLEAR_CTRL_BIT(EN_PIN);
return data;
}
void lcd_wait()
{
while(lcd_read(0) & 0x80); // wait until display is ready
}
void lcd_init()
{
_delay_ms(50); // wait for VDD to rise
lcd_write(0, 0x30);
_delay_ms(5);
lcd_write(0, 0x30);
_delay_ms(1); // _delay_us(120);
lcd_write(0, 0x30);
_delay_ms(1); // _delay_us(120);
lcd_write(0, 0x38); // 2 lines, normal font
_delay_ms(1);
lcd_write(0, 0xC); // display on
_delay_ms(1);
lcd_write(0, 1); // display clear
_delay_ms(1);
lcd_write(0, 0x6); // increment, don't shift
_delay_ms(1);
}
void lcd_puts(char * string)
{
char i;
lcd_write(0, 0x80); // move to 1st line
lcd_wait();
for(i=0; i<8; i++)
{
if(string[i] == '\0')
return;
lcd_write(1, string[i]);
lcd_wait();
}
lcd_write(0, 0x80+0x40); // move to 2nd line
lcd_wait();
for(i=8; i<16; i++)
{
if(string[i] == '\0')
return;
lcd_write(1, string[i]);
lcd_wait();
}
}
int main(void)
{
unsigned char i = 0;
char message[] = "nn Mississippi..";
DDRD = RS_PIN + EN_PIN + RW_PIN + LED_PIN; // Control outputs
DDRB = 0xFF; // Port B as DB0..DB7
lcd_init();
lcd_puts("Hello, World!!!");
_delay_ms(2000);
while(1)
{
if(++i >= 100)
i = 1;
if(i >= 10)
message[0] = i/10+'0';
else
message[0] = ' ';
message[1] = i%10+'0';
lcd_puts(message);
_delay_ms(1000);
}
return 1;
}
These define constants that have only the bit specified on
#define RW_PIN (1<<PD4) // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5) // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6) // PORTD Pin6 is defined as for EN
These Macros can then use the above can be used to set the bit (by OR'ing it on) or clearing the bit by using AND with the 1's complement of the constant (all bits on but one).
// macro or something else? confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)
Here is what it looks that the write is doing: If first puts all the port bits in output mode (so it can write the data). It then sets RW pin low (I assume to put it in write mode) and resets the display (if rs is set) by toggling the RS bit. It then loads the data into the DATA_PORT and toggles the EN pin (I assume to load it).
// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
if(DATA_PORT_DIR != 0xFF) // condition to test if DATA_PORT_DIR is true
//make DATA_PORT_DIR as output to write data to ldc
DATA_PORT_DIR = 0xFF;
CLEAR_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
DATA_PORT = data;
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
CLEAR_CTRL_BIT(EN_PIN);
}
Here is what it looks that the read is doing: If first puts all the port bits in input mode (so it can read the data). It then sets RW pin high (I assume to put it in read mode) and resets the display (if rs is set) by toggling the RS bit. It then sets the EN bit and fetches the data from the DATA_PORT and turns the EN pin off again.
unsigned char lcd_read(char rs)
{
unsigned char data;
if(DATA_PORT_DIR != 0)
DATA_PORT_DIR = 0;
SET_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
data = DATA_PORT_IN;
CLEAR_CTRL_BIT(EN_PIN);
return data;
}
Is that enough for you to figure out what the rest is doing?

USART embedded C. trigger character to store array

USART embedded c for atmega328p. trying to store an array of 10 characters of whatever user inputs after a certain character is received(in my case char $). This compiles for me but only outputs dollar signs when I input a string of chars using hercules utility reader. any help appreciated
the following is a copy of the code I am using
#define FOSC 16000000 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
#include <avr/io.h>
//#include <stdio.h>
char trig='$';
char arr[10];
//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(unsigned int ubrr)
{
//Set Baud rate
UBRR0H = (ubrr>>8);
UBRR0L = ubrr;
//Enable The receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
// Set fram format: 8data 2stopBit
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
unsigned char USARTReadChar( void )
{
//Wait untill a data is available
while(!(UCSR0A & (1<<RXC0)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR0;
}
//This function writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(unsigned char data)
{
//Wait untill the transmitter is ready
while(!(UCSR0A & (1<<UDRE0)))
{
//Do nothing
PORTD ^= 1 << PINB2;
}
//Now write the data to USART buffer
UDR0 = data;
}
int main(void)
{
DDRB |= 1 << PINB2;
//Varriable Declaration
char data;
USARTInit(MYUBRR);
//Loop forever
while(1)
{
//Read data
data = USARTReadChar();
int i =0;
//if incoming data is a dollar sign(trig),
if(data==trig)
{
//start a loop to collect data from buffer
for(i=0;i<10;i++)
{
//array has 10 elements, will fill up the ith element as per for loop
arr[i]=data;
// printf("arrayoutput %c\n",arr[i]);
USARTWriteChar(data);
}
}
}
}
I edited the while loop as suggested by oleg but still cannot get it to return the array .the entire code is as follows:
#define FOSC 16000000 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
#include <avr/io.h>
#include <stdio.h>
char trig='$';
char arr[10];
//This function is used to initialize the USART
//at a given UBRR value
void USARTInit(unsigned int ubrr)
{
//Set Baud rate
UBRR0H = (ubrr>>8);
UBRR0L = ubrr;
//Enable The receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
// Set fram format: 8data 2stopBit
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//This function is used to read the available data
//from USART. This function will wait untill data is
//available.
unsigned char USARTReadChar( void )
{
//Wait untill a data is available
while(!(UCSR0A & (1<<RXC0)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR0;
}
//This function writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(unsigned char data)
{
//Wait untill the transmitter is ready
while(!(UCSR0A & (1<<UDRE0)))
{
//Do nothing
PORTD ^= 1 << PINB2;
}
//Now write the data to USART buffer
UDR0 = data;
}
int main(void)
{
DDRB |= 1 << PINB2;
//Varriable Declaration
char data;
USARTInit(MYUBRR);
//Loop forever
//Read data
char input[10];
while(1){
data = USARTReadChar();
if(data == trig){
for(int i = 0; i < 10; i++){
//here we're saving 10 characters to input array
input[i] = USARTReadChar();
USARTWriteChar(input[i]);//tested without this also
}
}
}
}
Try to read chars in for() loop:
char input[10];
while(1){
data = USARTReadChar();
if(data == trig){
for(int i = 0; i < 10; i++){
//here we're saving 10 characters to input array
input[i] = USARTReadChar();
}
/* UPD: write stored array to console */
for(int i =0; i < 10; i++){
USARTWriteChar(input[i]);
}
/* those symbols are needed to emulate Enter button */
USARTWriteChar('\r');
USARTWriteChar('\n');
}
}
UPD: this code does exactly that you asked. It stores 10 chars in memory. To return them to console (utility reader) you have to use USARTWriteChar().

Resources