I have made a library for LCD with HD44780 controller in it, and from the datasheet I read that the code 0x18 will shift the entire display one position to the left, but when I made that, the display disappears.
I have also read that 0x1C shifts the entire display one position to the right but when I made it, the entire display shifts to left.
My code:
/*
* main.c
*
* Created: 11/14/2013 7:54:02 PM
* Author: A R M T
*/
#include <avr/io.h>
#define F_CPU 1000000UL
#define __DELAY_BACKWARD_COMPATIBLE__
#include <util/delay.h>
#define LCD_DPRT PORTA //LCD DATA PORT
#define LCD_DDDR DDRA //LCD DATA DDR
#define LCD_DPIN PINA //LCD DATA PIN
#define LCD_CPRT PORTB //LCD COMMANDS PORT
#define LCD_CDDR DDRB //LCD COMMANDS DDR
#define LCD_CPIN PINB //LCD COMMANDS PIN
#define LCD_RS 0 //LCD RS
#define LCD_RW 1 //LCD RW
#define LCD_EN 2 //LCD EN
//*************************************************************
void delay_us(unsigned int d);
void lcdCommand(unsigned char cmnd);
void lcdData(unsigned char data);
void lcd_init(void);
void lcd_gotoxy(unsigned char x, unsigned char y);
void lcd_print(char *str);
//*************************************************************
void delay_us(unsigned int d)
{
_delay_us(d);
}
//*************************************************************
void lcdCommand(unsigned char cmnd)
{
LCD_DPRT = cmnd; //send cmnd to data port
LCD_CPRT &= ~(1<<LCD_RS); //RS = 0 for command
LCD_CPRT &= ~(1<<LCD_RW); //RW = 0 for write
LCD_CPRT |= (1<<LCD_EN); //EN = 1 for H-to-l pulse
delay_us(1); //Wait to make enable wide
LCD_CPRT &= ~(1<<LCD_EN); //EN = 1 for H-to-l pulse
delay_us(100); //Wait to make enable wide
}
//*************************************************************
void lcdData(unsigned char data)
{
LCD_DPRT = data; //send data to data port
LCD_CPRT |= (1<<LCD_RS); //RS = 1 for data
LCD_CPRT &= ~(1<<LCD_RW); //RW = 0 for write
LCD_CPRT |= (1<<LCD_EN); //EN = 1 for H-to-L pulse
delay_us(1); //wait to make enable wide
LCD_CPRT &= ~(1<<LCD_EN); //EN = 0 for H-to-L pulse
delay_us(100); //wait to make enable wide
}
//*************************************************************
void lcd_init(void)
{
LCD_DDDR = 0xFF;
LCD_CDDR = 0xFF;
LCD_CPRT &= ~(1<<LCD_EN); //LCD_EN = 0
delay_us(15000); //wait for init
lcdCommand(0x38); //init. LCD 2 line, 5 * 7 matrix
lcdCommand(0x0E); //display on, cursor on
lcdCommand(0x01); //clear LCD
delay_us(2000); //wait
lcdCommand(0x06); //shift cursor right
}
//*************************************************************
void lcd_gotoxy(unsigned char x, unsigned char y)
{
unsigned char firstCharAdr[] = {0x80, 0xC0, 0x94, 0xD4};
lcdCommand(firstCharAdr[y-1] + x - 1);
delay_us(100);
}
//*************************************************************
void lcd_print(char *str)
{
unsigned char i = 0;
while (str[i] != 0)
{
lcdData(str[i]);
i++;
}
}
//*************************************************************
int main(void)
{
lcd_init();
lcd_gotoxy(1,1);
lcd_print("Armia");
lcd_gotoxy(1,2);
lcd_print("Wagdy");
_delay_ms(1000 / 2);
lcdCommand(0x18); // Shift the entire display one position to the left
while(1);
return 0;
}
I meant that when I burned this code I excepected that aftr(1000 / 2) ms this output will shift to left
but what appears was(the word disappears instead of shifting left one postition)
Can any one help me in that problem please?!
I tried your code in proteus version 7.10 and shift left works fine
Note that you are using the _delay_us function with a variable parameter, that is not the correct way, it gives wrong delays and generates big hex file because it forces the float library to be included
delay.h manual
Note:
In order for these functions to work as intended, compiler optimizations must be enabled, and the delay time must be an
expression that is a known constant at compile-time. If these
requirements are not met, the resulting delay will be much longer (and
basically unpredictable), and applications that otherwise do not use
floating-point calculations will experience severe code bloat by the
floating-point library routines linked into the application.
Replace the code with a loop that calls the delay several times
while (d--)
{
_delay_ms(1);
}
Related
Noob question:
I'm trying to learn about UART on an ARDUINO. I wrote some very simple code and for some reason, i can't make the receive() function work. I don't think it fetches the data from the UDR register. I'm using a small OLED display and i want to print the received data to it. No data is being printed to the display, when i run the code.
I connected the ports TX1 and RX1 with a wire on the board.
I tried finding youtube videos and have been reading alot. Appearently not enough.
Any ARDUINO expert who knows what to do?
#include <avr/io.h>
#include "ssd1306.h"
#include "I2C.h"
#include <stdio.h>
#include <util/delay.h>
void initOLED();
void initUART1();
void receive();
void transmit();
int main(void)
{
I2C_Init();
initOLED(); //initialiaze OLED
while (1)
{
transmit();
receive();
}
}
void initOLED()
{
I2C_Init();
InitializeDisplay();
clear_display();
}
void initUART1(void)
{
DDRD = 0x08; //TXD1 set to output
UBRR1L = 51; //Baudrate 19200
UBRR1H = 0; //upper four bits of baudrate
UCSR1A = 0x02; //Double speed mode
UCSR1B = 0x18; //Enable receive and transmit
UCSR1C = 0x06; //1 stop bit, 8-bit, no parity
}
void transmit()
{
char b = 'a';
while(!(UCSR1A & (1<<UDRE1))); //wait for an empty UDR register
UDR1 = b; //load character in register
}
void receive()
{
int Y = 0; //Y coordinate for cursor on the display
char d;
while(!(UCSR1A & (1<<RXC1))); //wait for unread data in the receive buffer
d = UDR1; //set UDR register in character d
sendCharXY(d, 1, Y); //send character to display
}
It looks like you never call initUART1().
I am a beginner in microprocessor programming. I created an array and sent datas using UART. I want to read a text file and create this array using datas in the text file with the simplest way possible. Any suggestion to proceed? Thanks in advance.
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define F_CPU 8000000UL // Clock freq
char flag = 0;
void usart_init(void){
UCSRA = 0x02;
UCSRB = 0x98; // Enable transmitter Enable receiver Enable Interrupt
UCSRC = (1<<UCSZ1) | (1<<UCSZ0); // set as 8 bit data, no parity bit and 1 stop bit.
UBRRH = 0x00;
UBRRL = 109;
}
int main(void){
usart_init();
while(1){
unsigned char array[5]={0x44,0xAA,0x33,0xBB,0x55};
for (int i=0;i<5;i++){
UDR = array[i];
UDR = 0xFF;
_delay_ms(100);
}
sei();
if(flag == 1)
{
flag = 0;
UCSRB = 0x98;
}
}
}
ISR(USART_RXC_vect){
UCSRB = (0<<RXEN)|(0<<TXEN)|(0<<RXCIE);
flag = 1;
}
You are working with a microcontroller so you can't handle a file directly. You had to code every value (copy & paste) in your source code.
unsigned char const array[5]={0x44,0xAA,0x33,0xBB,0x55};
You had to do this even for a large array.
I'm trying to get an arduino running C Code for a LCD display.
Compiling and transmitting and executing C code works fine, tried some LED flashing.
All wires should be OK too, when using the 'native' Arduino Library for LCD displays, everything works great, so it must be a code error I can't find :(
I'm trying to communicate with the LCD via 4 data-wire mode. Control and data pins are on the same port.
Here's the code:
//CPU-Clock Frequency
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
// Definitions:
#define LED_PIN PB5 //PB5 = Arduino Pin 13 (with LED)
#define COMPARE_REG OCR0A
#define TIMER_PIN OC0A
#define TIMER_CONTROL_REGISTER TCCR0A
#define LCD_PORT PORTD
#define LCD_PORTDIR DDRD
//controlpins:
#define RS_PIN PD0
#define RW_PIN PD1
#define ENABLE_PIN PD2
//datapins:
#define DB_7 PD7
#define DB_6 PD6
#define DB_5 PD5
#define DB_4 PD4
//Defined command parameters
#define CLEAR 0x01
// Methods
void sleep(uint16_t sleepTime){
for(;sleepTime>0;sleepTime--){ _delay_ms(1);}
}
void lcd_enable(){
LCD_PORT |= (1<<ENABLE_PIN);
//TODO: wait for busy?
sleep(5);
LCD_PORT &= !(1<<ENABLE_PIN);
sleep(5);
}
void lcd_pushOut(unsigned int data){
LCD_PORT &= (0x0F);
LCD_PORT |= (data & 0xF0);
lcd_enable();
LCD_PORT &= (0x0F);
LCD_PORT |= (data & 0x0F) << 4;
lcd_enable();
}
void lcd_command(unsigned int command){
unsigned short int tmp = (LCD_PORT & 0x0F); //speichere alte Steuerleitungen
LCD_PORT &= !(1<<RS_PIN);
lcd_pushOut(command);
LCD_PORT |= (1<<RS_PIN);
LCD_PORT |= tmp; //setze Steuerleitungen zurück
}
void lcd_init(){
sleep(15); //wait for LCD init
LCD_PORTDIR = 0xFF; //make port of LCD output.
LCD_PORT &= !(1<<RW_PIN); //write, dont read.
LCD_PORT |= (3<<4); //write '3' to port.
LCD_PORT &= !(1<<RS_PIN); //we give commands, not data!
lcd_enable();
sleep(1);
lcd_enable(); //write '3' to port 2nd time.
LCD_PORT &= 0x0F; //behalte steuersignale bei, setze daten'port' zurück.
LCD_PORT |= (2<<4); //write '2' to port.
lcd_enable();
//from now on LCD is in 4 bit mode.
lcd_pushOut(0x28); // 4 bit, 5x7 pix, 2 line mode
lcd_pushOut(0x06); //cursor rückt weiter, display scrollt
lcd_pushOut(0x0F); //display ein, cursor aus, blinken aus
lcd_pushOut(0x80); //we will write to DDRAM
lcd_pushOut(0x01); //clear display
//begin test writing zeroes.
LCD_PORT |= (1<<RS_PIN); //give data, not commands!
}
void timer_init(){
//DDRA |= (1<<TIMER_PIN); //make timerpin output.
TIMER_CONTROL_REGISTER = 0b10000000; //set timerpin high #bottom, on compare match clear. (0x80)
COMPARE_REG = 256/2; // dutycycle= 50%
}
void setTimerPower(unsigned int percent){ //set PWM Output (high) in %
COMPARE_REG = (percent/100) * 256;
}
int main (void)
{
//INIT
lcd_init();
//timer_init();
while(1){
lcd_command(CLEAR);
}
//now ready to write! let's write 3 zeroes!
lcd_pushOut('0');
lcd_pushOut('0');
lcd_pushOut('0');
/*
sleep(5000);
char c = '0';
while (1) {
lcd_clear();
lcd_pushOut(c++);
sleep(969); // 3x lcd_enable + 1 ms bearbeitungszeit? ... ziemlich großzügig
if(c > 0x7A) //entspricht c > 'z'
c='0';
}
*/
return 0;
}
EDIT: most of the time, LCD just makes black squares all over the first line.
All instances of !(1<<BIT_NUMBER) should be converted to ~(1<<BIT_NUMBER) as ! is a boolean NOT and you're essentially doing !(true) so you get 0 as a result.
Example showing the problem (on x86):
int main( int argc, char* argv[] )
{
printf( "%8.8X %8.8X\n", !(1<<2), ~(1<<2) );
return 0;
}
And output is:
00000000 FFFFFFFB
Change that and you'll at least be further ahead. You should also state which controller is on the LCD to help any further.
I am writing a code for a MCU until that will transmit data via UART (RS232).
[ATmega8A]
Currently, I am testing my code in Proteus:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <compat/twi.h>
#define FOSC 16000000 //Clock Speed
#define BAUD 9600 //Baud rate set to 9600
#define MYBRR FOSC/16/BAUD-1
void USART_Init (void)
{
UBRRH = (MYBRR >> 8); //Code for setting
UBRRL = MYBRR; //the baud rate
UCSRB = (1 << RXEN) | (1 << TXEN); //Enable receiver and transmitter
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); //Frame format setting: 8 Data, 2 Stop bit
}
/* USART transmit function */
void USART_Transmit(unsigned char data)
{
while(!(UCSRA & (1 << UDRE))); //Wait until transmit buffer is empty
UDR = data;
}
/* USART receive function */
unsigned char USART_Receive(void)
{
while(!(UCSRA & (1 << RXC))); //Wait until data is received
return UDR; //Get the data from buffer and return it
}
and the test code in main:
int main(void)
{
unsigned char c;
while(1)
{
a = USART_Receive();
c = 10;
USART_Transmit(c);
_delay(10000);
}
}
In Proteus, the virtual terminal displays 0. However, I am expecting to see 10.
This is just one example, in general only the last digit/character is getting displayed on the virtual terminal.
I cannot explain this. Proteus bug or logic error?
Thank you for any advise.
UART data is sent only in ascii format...you have to convert the integer data to ascii format..use itoa() or do this one
int main(void)
{
unsigned char c;
unsigned char b;
while(1)
{
a = USART_Receive();
c = 10;
b=c;
b=c/10;
USART_Transmit(b+48);
b=0;
b=c%10;
USART_Transmit(b+48);
_delay(10000);
}
}
I am running a C program on an AVR chip. Whenever a serial signal is heard, it runs the serial interrupt ISR (USART_RX_vect). In this method it should turn on change to = 1;. Then in my main while loop, it should clear the LCD and display it and then set change = 0 again.
This is to stop it continually doing the calulations, and displaying the result on the LCD a million times a minute..
However, when the interrupt method changes the change variable to 1, it does not seem to change it "globally" and in the main method it is always 0..
There is a bit of stuff in here that is for debugging purposes.
/* LCD DEFINES */
#define LED PB5
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
/* UART SERIAL DEFINES */
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#define STARTCHAR 'R'
#define ENDCHAR 'E'
char reading;
char inputBuffer[12];
char readStatus;
uint8_t position;
int change;
char output;
int result;
struct Axis
{
uint8_t axisNumber;
uint16_t position;
uint16_t oldPosition;
} axis1, axis2, axis3;
/* SETUP UART */
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit( unsigned char data )
{
UDR0 = data;
}
unsigned char USART_Receive( void )
{
return UDR0;
}
/*****************************************************************/
int main(void)
{
/* INITALISE SERIAL */
USART_Init(MYUBRR);
/* Turn on Receive Complete Interrupt */
UCSR0B |= (1 << RXCIE0);
/* Turn On GLobal Interrupts */
sei();
position = 0;
change = 0;
/* Initialise LCD */
lcd_init(LCD_DISP_ON); /* Initialize display, cursor off. */
lcd_clrscr();
lcd_puts("READY");
//Turn on LED 13
set_output(PORTB,LED);
output_low(PORTB,LED);
while (1) /* Loop forever */
{
if (change == 1)
{
//If not reading, display the result on the LCD display.
axis1.position = (inputBuffer[0]<< 8) | inputBuffer[1];
axis2.position = (inputBuffer[2]<< 8) | inputBuffer[3];
axis3.position = (inputBuffer[4]<< 8) | inputBuffer[5];
char axis1Printout[12];
char axis2Printout[12];
char axis3Printout[12];
sprintf(axis1Printout,"%u ", axis1.position);
sprintf(axis2Printout,"%u ", axis2.position);
sprintf(axis3Printout,"%u ", axis3.position);
char output[40] = "";
strcat(output, axis1Printout);
strcat(output, axis2Printout);
//strcat(output, axis3Printout);
lcd_clrscr(); /* Clear the screen*/
lcd_puts(output);
_delay_ms(300);
change = 0;
}
}
}
/* INTERRUPTS */
ISR (USART_RX_vect)
{
change = 1;
unsigned char input = USART_Receive();
if (input == 'R')
{
readStatus = 0; //Reading
position = 0;
}
else if ((input != 'E') && (position < 12) && (position > -1))
{
inputBuffer[position] = input;
position++;
}
else if (input == 'E')
{
readStatus = 1; //Stop Reading
position = -1;
output_high(PORTB,LED);
}
}
You need to declare change using the volatile keyword:
volatile int change;
This tells the two 'threads' (main execution loop and your ISR code) to not 'cache' the value in a register, but always retrieve it from memory.
Edit: There's another problem with the code - in your main loop, by the time you set changed to 0, you may have already had another interrupt which should have triggered your loop to run again. The easy-but-not-guaranteed fix is to immediately set changed to 0 straight after you check it. The proper way would be to use a lock - but depending on your situation, the first option might do.
Make the variable declaration volatile to ensure that a changed value is written imediately to the variable in memory.
An object shared by an interrupt handler and the application code should be qualified as volatile in the declaration.
Without the qualifier, the implementation can assume the object cannot change unexpectedly in the application code and can cache the variable (in a register for example) for optimizations while executing the application code.