I use a PIC16F690 for communication with my LCD. I got the following code from an example. The problem is that I want to use the 4 lower bits for my own outputs, but it always gets overwritten. The problem is, that I always overwrite the complete port. How can I only write the 4 upper bits without touching the first 4.
#define LCD_DATA PORTC
void lcd_write (unsigned char c)
{
__delay_ms(1);
LCD_DATA = ((c >>4) & 0x0F);
LCD_STROBE();
LCD_DATA = (c & 0x0F);
LCD_STROBE();
}
void lcd_init()
{
char init_value;
ANSEL= 0; //Disable analog pins on PORTA
init_value= 0x3;
LCD_RS= 0;
LCD_EN= 0;
__delay_ms(100);
__delay_ms(15); //wait 15ms after power is applied
LCD_DATA = init_value;
LCD_STROBE();
__delay_ms(10);
LCD_STROBE();
__delay_ms(10);
LCD_DATA =2; //4-bit mode
LCD_STROBE();
lcd_write(0x28); //Set interface length
lcd_write(0x0C); //Display On, Cursor On, Cursor Blink
lcd_clear(); //Clear Screen
lcd_write(0x6); //Set entry mode
}
Hope you guys can help me :)
Edit:
Thank you for your hints. Found following solution and works perfectly or do i miss something?
void lcd_write (unsigned char c)
{
__delay_ms(1);
if(((c >>4) & 1))
{
RC0 = 1;
}else
{
RC0 = 0;
}
if(((c >>4) & 2))
{
RC1 = 1;
}else
{
RC1 = 0;
}
if(((c >>4) & 4))
{
RC2 = 1;
}else
{
RC2 = 0;
}
if(((c >>4) & 8))
{
RC3 = 1;
}else
{
RC3 = 0;
}
//LCD_DATA = ((c >>4) & 0x0F);
LCD_STROBE();
//LCD_DATA = (c & 0x0F);
if(c & 1)
{
RC0 = 1;
}else
{
RC0 = 0;
}
if(c & 2)
{
RC1 = 1;
}else
{
RC1 = 0;
}
if(c & 4)
{
RC2 = 1;
}else
{
RC2 = 0;
}
if(c & 8)
{
RC3 = 1;
}else
{
RC3 = 0;
}
LCD_STROBE();
}
Unfortunately, your PIC model lacks LAT registers, which could allow you to write a cleaner and simplified code. If you had them, you could apply read-modify-write method. PIC18 and the latest PIC16 models have LAT registers.
If the uC has LAT registers, you can write it like this:
#define LCD_DATA LATC // Instead of PORTC
void lcd_write (unsigned char c)
{
__delay_ms(1);
unsigned char oldValue = LCD_DATA & 0xF0;
LCD_DATA = (oldValue | ((c >> 4) & 0x0F));
LCD_STROBE();
LCD_DATA = (oldValue | (c & 0x0F));
LCD_STROBE();
}
This may still work with PORTC, but it's risky to use it and it may be unreliable. Because reading from PORT register reads the current status of the port, not the output latch. But I suggest you to try it yourself and see the result. If there is sufficient time between the latch write accesses, the hardware pin output may have enough time to stabilize and it may work.
Related
I am new to programming in IDE. I am using built-in timer of arduino.I am using TDR method to capture reflection from fault location in cable and for that I am using timer.Timer should start as soon as output is send and stop at reflection. I have a reference code for it but I dont able to understand it, so if anyone know about it , it would be great.
void setup()
{
pinMode(stepPin, OUTPUT);
pinMode(refPin, OUTPUT);
pinMode(shutdownPin, OUTPUT);
TCCR1A = 0;
TCCR1B = (1 << ICNC1); // input capture noise canceller enabled, capture on falling edge
TIMSK1 = 0; // timer 1 interrupts disabled
ACSR = 0; // input capture from ICP1 pin
TCCR2B = (1 << CS20); // change timer 2 PWM frequency to 31.25kHz because we're using pin 11 as a DAC
Serial.begin(19200);
}
struct Step
{
unsigned int time;
unsigned int amplitude;
};
// Take a single measurement, using either a positive or negative edge from the comparator.
// The comparator reference voltage must have been set up and allowed to stablise before calling this.
unsigned int takeMeasurement(bool posEdge)
{
byte reg1b = (posEdge) ? 0 : (1 << ICES1); // input capture noise canceller csdisabled, set up input capture polarity, stop timer
reg1b |= (1 << CS10);
TCCR1B = reg1b;
TCNT1H = 0;
TCNT1L = 0; // clear timer
unsigned int capture = 0;
unsigned long start = micros(); // get the time
cli();
TCNT1H = 0;
TCNT1L = 0; // clear timer
TIFR1 = (1 << ICF1); // clear timer 1 input capture bit
PORTD |= (1 << 4); // set output high
sei();
do
{
if ((TIFR1 & (1 << ICF1)) && capture == 0)
{
byte temp = ICR1L;
capture = (ICR1H << 8) | temp;
}
} while (micros() - start < 100);
PORTD &= ~(1 << 4); // set output low
return capture;
}
size_t findSteps(bool positive, struct Step *results, size_t maxResults)
{
byte amplitude = (positive) ? 5 : 250;
analogWrite(refPin, amplitude);
delay(100); // wait 100ms for the output to stabilise
unsigned int lastReading = 0;
size_t numResults = 0;
unsigned int stepSize = 0; // 0 means not in a step
#ifdef DEBUG
Serial.print((positive) ? "pos " : "neg ");
#endif
for (int i = 0; i < 50; ++i)
{
analogWrite(refPin, amplitude);
delay(10);
unsigned int currentReading = takeMeasurement(positive);
unsigned int currentDiff = currentReading - lastReading; // diff since start of possible step
if (stepSize == 0)
{
// Not currently in a step
if (i != 0 && currentReading != 0 && currentDiff == 0)
{
// Found the start of a possible step
++stepSize;
}
lastReading = currentReading;
}
else
{
if (currentDiff > 2 || i + 1 == 50)
{
// Step has endeed, so record it if it is big enough
if (stepSize >= 2)
{
results->time = lastReading;
results->amplitude = amplitude - 5;
++results;
++numResults;
if (numResults == maxResults) break;
}
stepSize = 0;
lastReading = currentReading;
}
else if (currentDiff == 0)
{
++stepSize;
}
}
#ifdef DEBUG
if (i != 0) Serial.write(',');
Serial.print(currentReading);
#endif
if (positive)
{
amplitude += 5;
}
else
{
amplitude -= 5;
}
}
#ifdef DEBUG
Serial.println();
#endif
return numResults;
}
So I got this very strange problem that happens every time. I am trying to interface and LCD with the MSP430 module. But in this function at the middle of the loop, the variable i resets itself to 0 for no apparent reason at all, somethimes it even crashes. This is the structure of the lcd_t struct:
struct lcd_t
{
uint8_t rs, rw, e;
uint8_t pin[8];
};
This is the function where i is defined and "reseted":
void
lcd_dat(const struct lcd_t* lcd, uint8_t dat)
{
static uint8_t i;
// Setting RS.
//
lcd_change_pin_state(lcd->rs, 1);
// Setting each data pin to match the dat.
//
for(i = 0; i < 8; i++) // TODO: Four bit mode
{
if(dat & (1 << i))
{
lcd_change_pin_state(lcd->pin[i], 1);
}
else
{
lcd_change_pin_state(lcd->pin[i], 0); <-- This is where i resets
}
}
// Setting E.
//
lcd_change_pin_state(lcd->e, 1);
__delay_cycles(2*1000);
// Clearing E.
//
lcd_change_pin_state(lcd->e, 0);
}
This is the function where i resets:
static volatile void
lcd_change_pin_state(uint8_t pin, uint8_t newstate)
{
if(newstate == 0)
{
if(pin/10 == 1)
{
P1OUT &= ~(1 << (pin % 10));
}
else
{
P2OUT &= ~(1 << (pin % 10));
}
}
else
{
if(pin/10 == 1)
{
P1OUT |= (1 << (pin % 10));
}
else
{
P2OUT |= (1 << (pin % 10));
}
}
}
Plese tell me what other information do you need! Thanks!
WDTCTL = WDTPW + WDTHOLD; // stop watchdog timer
This instruction was missing...
I can't even think how much time was lost because of this...
I want to initialize an SD card manually from an Arduino Mega 2560 and read its contents.
I've read a lot of manuals explaining how to properly do it, as well as the Arduino SD library code, but I can't get it to work.
uint8_t spi_byte(uint8_t byte) {
SPDR = byte;
asm volatile("nop");
while(!(SPSR & B10000000));
uint8_t response = SPDR;
return response;
}
uint8_t sd_cmd(uint8_t cmd, uint32_t args) {
if(cmd != 0x40) while(spi_byte(0xFF) != 0xFF);
spi_byte(cmd);
int8_t c;
for(c = 3; c >= 0; --c) spi_byte(args >> (c << 3));
uint8_t crc;
if(cmd == 0x40) crc = 0x95;
else if(cmd == 0x48) crc = 0x87;
else crc = 0xFF;
spi_byte(crc);
uint8_t response;
for(c = 16; ((response = spi_byte(0xFF)) & 0x80) && c; --c);
/*if((cmd < 0x51) || (cmd > 0x59))*/ spi_byte(0xFF); //S
return response;
}
void sd_init() {
DDRB &= B11110000;
PORTB |= B0001; //set CS pull-up resistor (just-in-case)
DDRB |= B0001; //set CS to output
PORTB |= B1000; //set MISO pull-up resistor (just-in-case)
SPCR = B01010010; //no interrupt, MSB first, master, mode 0, fosc/64 (250 kHz)
SPSR &= ~1; //clear SPI double speed
DDRB |= B0110; //set SCK and MOSI to output
delayMicroseconds(200000);
uint8_t c;
cli();
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
clb(PORTB, 0); //set CS low
uint8_t response;
uint16_t timeout = 1024;
while((response=sd_cmd(0x40, 0)) != 0x1) { //CMD0: reset card
if((!response) || (response == 0xFF)) error(3); //we don't even have a card
if(!--timeout) error(7); //timed out
}
if(sd_cmd(0x48, 0x1AA) != 1) error(1); //CMD8: make sure we are using SD v2
for(c = 0; c < 4; ++c) spi_byte(0xFF);
do {
sd_cmd(0x77, 0); //CMD55: introduce application-specific command
response = sd_cmd(0x69, 0x40000000); //ACMD41: initialize card
if(!--timeout) error(8); //timed out
} while(response != 0);
sd_cmd(0x7A, 0); //CMD58: read OCR
response = spi_byte(0xFF);
if((response & B11000000) != B11000000) error(2); //make sure we are using SDHC
for(c = 0; c < 3; ++c) spi_byte(0xFF);
stb(PORTB, 0); //set CS high
SPCR = B01010000; //fosc/4 (4 MHz)
SPSR |= 1; //set SPI double speed (8 MHz)
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
sei();
return;
}
void sd_read(uint8_t* buffer, uint32_t block, uint8_t start2, uint8_t size2) {
/*start2 and size2 are in 2 byte units, size2 = 0 means whole block (512 B)*/
cli();
block <<= 9; //S//D
clb(PORTB, 0); //set CS low
uint8_t response;
if((response=sd_cmd(0x51, block))) { //CMD17: read single block
Serial.begin(9600); //D
Serial.println(response, HEX); //D
error(10);
}
while(spi_byte(0xFF) != 0xFE) ; //TODO: timeout error 9
uint8_t b = 0; uint8_t end = 0;
do {
if((b >= start2) && (!end)) {
*(buffer++) = spi_byte(0xFF);
*(buffer++) = spi_byte(0xFF);
--size2;
if(!size2) end = 1;
}
else {
spi_byte(0xFF);
spi_byte(0xFF);
}
++b;
} while(b); //repeat 256 times
spi_byte(0xFF); spi_byte(0xFF); //two more bytes to close
stb(PORTB, 0); //set CS high
spi_byte(0xFF);
sei();
return;
}
Some days it works perfectly, other times it just locks up at initialization time, and finally right now I'm trying to read SD card contents and it just displays 0x55AA forever. I suspect that it is a hardware problem, but I'd like to rule out the possibility that my code might be wrong. Also, I don't know why I have to multiply reading address by 512. Being this an SDHC card, I would expect addresses to be in blocks, right?
I am trying to turn on the LEDs when the user button is pressed
I think I have enabled the peripheral clocks right and the right register. The button is on porta bit 0
Here is my code...any help would be great. Sorry if it is a bit simple, I am still learning the board.
int main (void)
{
RCC->AHB1ENR=0x9;
GPIOA->MODER = 0x00000002;
GPIOD->MODER = 0x55000000;
GPIOD->OTYPER = 0;
GPIOD->OSPEEDR = 0;
GPIOD->PUPDR = 0;
GPIOA->PUPDR = 0;
GPIOA->OTYPER = 0;
GPIOA->OSPEEDR = 0;
while(1)
{
if(GPIOA->IDR == 0x0001){
GPIOD->ODR = 0xF000;
}
else{
GPIOD->ODR = 0;
}
}
}
I don't know the STM32f4 but I'm guessing that instead of
if(GPIOA->IDR == 0x0001)
You want
if ((GPIOA->IDR & 0x0001) != 0)
The original checks that the low bit is on AND all other bits are off while the new version just checks the low bit and ignores the rest.
I have a C program that I am trying to put on my pic but I get the error "3.17 can't open include file "main.h": No such file or directory". This is my first time ever attempting to program a pic.
Here is the program I am trying to put on it.
#include <htc.h>
#include <stdio.h>
#include "main.h"
__CONFIG(FOSC_INTOSC & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_OFF & IESO_OFF & FCMEN_OFF);
__CONFIG(WRT_OFF & PLLEN_OFF & STVREN_OFF & BORV_HI & LVP_OFF);
#define _XTAL_FREQ 4000000
int main()
{
int t = 0;
char outStr[8];
char ch;
init();
Lcd_PutStr(0, 0, "Option 1");
Lcd_PutStr(1, 0, "Spec Analyzer");
while (1)
{
// do stuff here
}
}
int init()
{
// Hardware
OSCCON = 0x6A; // 4 MHz oscillator
PORTA = 0; // Clear Port A
LATA = 0;
PORTB = 0; // Clear Port B
LATB = 0;
PORTC = 0; // Clear Port C
LATC = 0;
ANSELA = 0; // Set Port A to digital
ANSELB = 0; // Set Port B to digital
ANSELC = 0; // Set Port C to digital
TRISB = 0; // Set port B to output
TRISC = 0; // Set port C to output
// LCD display
Lcd_Init();
return 0;
}
void ENPulse()
{
LATC |= 0x20;
__delay_us(1);
LATC &= 0xdf;
}
void Lcd_Init()
{
LATC = 0;
__delay_ms(40);
LATC = 0x03;
ENPulse();
__delay_us(37);
Lcd_Cmd(0x28);
__delay_us(37);
Lcd_Cmd(0x28);
__delay_us(37);
Lcd_Cmd(0x0C);
__delay_ms(2);
Lcd_Cmd(0x01);
__delay_us(37);
}
void Lcd_Cmd(byte cmd)
{
LATC = cmd >> 4;
ENPulse();
LATC = cmd & 0x0F; // clear RS (LATC,4)
ENPulse();
__delay_us(100);
}
void Lcd_Data(byte data)
{
LATC = (data >> 4) | 0x10; // set RS (LATC,4)
ENPulse();
LATC = (data & 0x0F) | 0x10; // set RS (LATC,4)
ENPulse();
__delay_us(100);
}
void Lcd_PutStr(int row, int col, char* str)
{
int pos;
// use row and column=-1 for no positioning, i.e. position where last ended
if (row >= 0 && col >= 0)
{
if (row > 0)
row = 0x40; // row 1
else
row = 0; // row 0
pos = row | col | 0x80; // 0x80 is cmd for positioning cursor
Lcd_Cmd(pos);
}
while (*str)
{
Lcd_Data(*str);
str++;
}
}
I am using MPLab and Hi-Tech C with a Pickit3. I based this code off of a sample given to me. I do not know what the purpose of the main.h file is. Any help is appreciated.
After reviewing your errors, you may be able to run the code without main.h. It looks like main.h mostly prototypes the functions at the bottom of the file. Try putting this code between the main and the #define:
int init();
void ENPulse();
void Lcd_Init();
void Lcd_Cmd(byte cmd);
void Lcd_Data(byte data);
void Lcd_PutStr(int row, int col, char* str);
This should at lest reduce most of your errors. It may fix it completely. The idea is that when the compiler first encounters theses functions it doesn't know what they are and it throws errors before it can find them. If there are still errors let me know and I'll try and help more.
Try this code:
#include <htc.h>
#include <stdio.h>
//#include "main.h"
__CONFIG(FOSC_INTOSC & WDTE_OFF & PWRTE_OFF & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_OFF & IESO_OFF & FCMEN_OFF);
__CONFIG(WRT_OFF & PLLEN_OFF & STVREN_OFF & BORV_HI & LVP_OFF);
#define _XTAL_FREQ 4000000
int init()
{
// Hardware
OSCCON = 0x6A; // 4 MHz oscillator
PORTA = 0; // Clear Port A
LATA = 0;
PORTB = 0; // Clear Port B
LATB = 0;
PORTC = 0; // Clear Port C
LATC = 0;
ANSELA = 0; // Set Port A to digital
ANSELB = 0; // Set Port B to digital
ANSELC = 0; // Set Port C to digital
TRISB = 0; // Set port B to output
TRISC = 0; // Set port C to output
// LCD display
Lcd_Init();
return 0;
}
void ENPulse()
{
LATC |= 0x20;
__delay_us(1);
LATC &= 0xdf;
}
void Lcd_Init()
{
LATC = 0;
__delay_ms(40);
LATC = 0x03;
ENPulse();
__delay_us(37);
Lcd_Cmd(0x28);
__delay_us(37);
Lcd_Cmd(0x28);
__delay_us(37);
Lcd_Cmd(0x0C);
__delay_ms(2);
Lcd_Cmd(0x01);
__delay_us(37);
}
void Lcd_Cmd(byte cmd)
{
LATC = cmd >> 4;
ENPulse();
LATC = cmd & 0x0F; // clear RS (LATC,4)
ENPulse();
__delay_us(100);
}
void Lcd_Data(byte data)
{
LATC = (data >> 4) | 0x10; // set RS (LATC,4)
ENPulse();
LATC = (data & 0x0F) | 0x10; // set RS (LATC,4)
ENPulse();
__delay_us(100);
}
void Lcd_PutStr(int row, int col, char* str)
{
int pos;
// use row and column=-1 for no positioning, i.e. position where last ended
if (row >= 0 && col >= 0)
{
if (row > 0)
row = 0x40; // row 1
else
row = 0; // row 0
pos = row | col | 0x80; // 0x80 is cmd for positioning cursor
Lcd_Cmd(pos);
}
while (*str)
{
Lcd_Data(*str);
str++;
}
}
int main()
{
int t = 0;
char outStr[8];
char ch;
init();
Lcd_PutStr(0, 0, "Option 1");
Lcd_PutStr(1, 0, "Spec Analyzer");
while (1)
{
// do stuff here
}
}