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.
Related
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.
I have tried to implement TX only uart for ATTiny85 and receive the bits using arduino micro. (similiar question did not help since it is quite different to my situation)
My intend is to be able to print via attiny85 -> arduino -> console so I can debug the attiny85, since I don't have oscilloscope available.
attiny85 fuses are: "efuse:w:0xff:m -U hfuse:w:0xdf:m -U lfuse:w:0xf1:m" aka. 16MHz F_CPU
arduino also seems to have 16MHz F_CPU
Similiar to the mentioned question attiny85 sends bits via timer0 ISR one bit at time:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TX_PIN PB0
volatile uint16_t tx_shift_reg = 0;
ISR(TIMER0_COMPA_vect) {
uint16_t local_tx_shift_reg = tx_shift_reg;
if( local_tx_shift_reg & 0x01 ) {
PORTB |= _BV(TX_PIN);
} else {
PORTB &= ~_BV(TX_PIN);
}
local_tx_shift_reg >>= 1;
if(!local_tx_shift_reg) {
// Stop timer0.
GTCCR |= (1<<TSM) | (1<<PSR0);
}
tx_shift_reg = local_tx_shift_reg;
}
void UART_tx(char byte) {
uint16_t local_tx_shift_reg = tx_shift_reg;
local_tx_shift_reg = (0b1<<9) | ((uint16_t)byte<<1);
tx_shift_reg = local_tx_shift_reg;
TCNT0 = 0;
TCCR0B |= (1<<CS02)|(1<<CS00); // 1024 prescaler
GTCCR &= ~(1<<TSM);
}
void UART_tx_char(char c) {
UART_tx( c );
// wait until transmission is finished
while(tx_shift_reg);
}
void UART_init() {
cli()
// set TX pins as output
DDRB |= (1<<TX_PIN);
PORTB |= (1<<TX_PIN);
// set timer0 to CTC mode, keep it halted.
TCCR0A |= (1<<WGM01);
TCCR0B = 0;
// enable interrupt
TIMSK |= (1<<OCIE0A);
OCR0A = 128;
OCR0B = 128;
TCNT0 = 0;
GTCCR |= (1<<TSM);
sei();
}
void main(void)
{
UART_init();
while(1) {
for(char c = 1; c < 128; ++c) {
UART_tx_char(c);
_delay_ms(100);
}
}
}
Then arduino receives the bits:
/*
* ATtiny85 bit-bang uart monitor for ATmega32u4
*/
#define LED_PIN 13
#define RX_PIN 7
// rx_state == 0 // timer1 not running
// rx_state == 1 // receive in progress
// rx_state == 2 // data ready in rx_data_reg
volatile int rx_state = 0;
volatile int rx_bit_nro = 0;
volatile uint16_t rx_shift_reg = 0;
volatile uint16_t rx_data_reg = 0;
void rx_start_interupt() {
if(rx_state == 0) {
digitalWrite(LED_PIN, HIGH);
while(digitalRead(RX_PIN));
// Start timer1
rx_state++;
TCNT1 = 0;
TCCR1B = (1 << WGM12) | (1 <<CS12) | (1 << CS10);
}
}
ISR(TIMER1_COMPA_vect) {
uint16_t bit = digitalRead(RX_PIN) > 0;
rx_shift_reg >>= 1;
rx_shift_reg |= (bit << 7);
++rx_bit_nro;
if(rx_bit_nro == 9) {
// Stop timer.
TCCR1B = 0;
TCNT1 = 0;
rx_data_reg = rx_shift_reg;
rx_shift_reg = 0;
rx_bit_nro = 0;
rx_state++;
digitalWrite(LED_PIN, LOW);
}
}
void setup() {
noInterrupts();
// Program timer1 for UART bit bang receive.
TCCR1A = 0; // set entire TCCR1A register to 0 (stops it)
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
OCR1A = 128;
TIMSK1 |= (1 << OCIE1A);
interrupts();
pinMode(LED_PIN, OUTPUT);
pinMode(RX_PIN, INPUT);
// Attach RX start interupt.
pinMode(digitalPinToInterrupt(RX_PIN), INPUT);
attachInterrupt(digitalPinToInterrupt(RX_PIN), rx_start_interupt, FALLING);
Serial.begin(9600);
while(!Serial);
Serial.print("F_CPU:");
Serial.println(F_CPU,DEC);
Serial.println("Waiting for data from attiny85...");
}
void loop() {
if(rx_state == 2) {
uint16_t local_rx_data = rx_data_reg;
rx_state = 0;
Serial.println(local_rx_data,HEX);
}
}
I have tried pretty much everything to make it work, but received bytes come back garbace.
What am I missing?
Note: I'm using timer0 on attiny85 and timer1 on arduino.
Solved: switching ISR to TIMER1_COMPAB_vect and OCR1B = 64 actually works! Yay!
I recently ran into this issue of serial comms coming out as garbage on the other end. In my case, the ATtiny85 was sending bits to my laptop using an USB to TTL UART converter which had worked beautifully in other situations, but, I was just getting garbage in the Arduino IDE serial monitor.
I found a forum post which mentioned the possibility of calibrating OSCCAL.
I get a little bit fancier in my related blog post, but I tested the theory that I should calibrate OSCCAL using this code:
#include <SoftwareSerial.h>
SoftwareSerial comm(-1, 0);
static const int anchor = 128;
void
print_osccal(int v) {
comm.println(F("********************************"));
comm.print(F("OSCCAL = "));
comm.println(v);
comm.println(F("********************************"));
}
void
setup() {
delay(5000);
comm.begin(300);
OSCCAL = anchor;
print_osccal(anchor);
delay(5000);
}
void
loop() {
int x;
for (int i = 1; i < 128; ++i) {
x = anchor + i;
OSCCAL = x;
print_osccal(x);
delay(1000);
x = anchor - i;
OSCCAL = x;
print_osccal(x);
delay(1000);
}
}
It was a revelation seeing garbage all of a sudden transform to nicely formatted messages in the serial monitor (and, of course, back to garbage as the search is an infinite loop).
Now, the ATtiny85's internal oscillator can only support 1 MHz and 8 MHz. As I understand it, OSCCAL exists because this internal oscillator is 1) not very accurate and 2) is very sensitive the temperature.
If the ATtiny85 is set to run at 16MHz, it needs a reliable, external oscillator, and no amount of fiddling with OSCCAL might help. But, it did in my case allow me to discover the value(s) which made SoftwareSerial tick at 8 MHz and a range of baud rates from 300 to 38400.
This allowed me to get the right value for the bit banging UART to work with the 1MHz clock which is not supported by SoftwareSerial.
I'm in a microprocessors class and we're writing our own delay functions that are actually accurate. Our professor gave us, what I assume is, a 4 ms delay function. I don't really understand how to transfer that to a .25 s or a 1 s delay, which are both needed for my homework.
The given function is as follows(Assume _BV() is defined as _BV(x) 1<<(x)):
DDRB |= _BV(1);
TCCR1A |= _BV(COM1A0);
TCNT1 = 0;
OCR1A = 100;
TIFR1 = _BV(OCF1A);
TCCR1B |= _BV(CS10);
while((TIFR1 & _BV(OCF1A)) == 0);
TIFR1 = _BV(OCF1A);
OCR1A = 100 + 64000;
while((TIFR1 & _BV(OCF1A)) == 0);
TCCR1B = 0;
TCCR1A = 0;
I've written the code needed to complete the homework except the two delay functions.
Here is what I have so far:
#include <avr/io.h>
uint8_t numIN;
void setup() {
Serial.begin(9600);
DDRB |= _BV(5);
}
void loop() {
int i;
numIN = 10;
Serial.println("Enter a number between 0 and 9.");
do {
while (Serial.available() > 0)
{
numIN = Serial.read() - '0';
if (numIN < 0 || numIN > 9)
{
Serial.println("Input Error!");
}
}
} while (numIN < 0 || numIN > 9);
Serial.print("You entered ");
Serial.println(numIN);
if (isEven(numIN))
{
for (i = 0; i < 5; i++)
{
PORTB |= _BV(5);
delay(1000); //temporary
//delay_Sec();
PORTB &= ~_BV(5);
delay(1000); //temporary
//delay_Sec();
}
}
else
{
for (i = 0; i < 5; i++)
{
PORTB |= _BV(5);
delay(250); //temporary
//delay_quarterSec();
PORTB &= ~_BV(5);
delay(250); //temporary
//delay_quarterSec();
}
}
}
void delay_quarterSec(void)
{
//need to finish
}
void delay_Sec(void)
{
//need to finish
}
boolean isEven(int num)
{
if (num & _BV(0))
return false;
else
return true;
}
I'm just confused how I take my professor's code and transfer it to what I need to do. Any help is greatly appreciated!
I can give you a quick overview about what the provided code does.
(This is from memory, so don't take my word for it. And you don't mention your controller type. You will have to look up the registers up in detail.)
DDRB |= _BV(1); // set the compare match output pin to output
TCCR1A |= _BV(COM1A0); // enable output compare PIN toggle
TCNT1 = 0; // set counter start value to 0
OCR1A = 100; // set compare match value to 100 (the actual delay)
TIFR1 = _BV(OCF1A); // clear the output compare flag
TCCR1B |= _BV(CS10); // enable the timer by setting the pre-scaler
while((TIFR1 & _BV(OCF1A)) == 0); // wait until the timer counted to 100 (compare flag is set again)
So the actual delay depends on:
the setting of the prescaler
the clock speed of your controller
the value of OCR1A
Example:
If the prescaler is set to 1 and you run at 10MHz you got
t = (1 / (10000000/s)) * 100 = 10us
This should get you started.
I need to program a PIC16F883 to blink / light up LED's at the same time. The oscillator is running at 3,2768, and I'm using TIMER0 to help me with the timing.
Right now, I have a prescaler set to 1:256, so I get an interrupt every 50ms, and I have a variable that is calculated from that, to display how many seconds has gone.
If the input is changed, the seconds variable is of course reset again.
Here is the assignment from my teacher:
If Input is 0 (Closed):
The Red And The Green LED should be turned on at the same time for 15 seconds. After this the green LED should be turned
off completely, and the red LED should blink every fifth second for 10 minutes
If input is 1 (Opened):
The red LED should be turned off completely, and the green LED should be turned on for 10 minutes, and after that
it should be turned off too.
My timer is working fine. I have tested that. The program runs fine too and keeps the 2 LED's turned off for 15 seconds, then turns them off, but my red LED isn't blinking. I have been sitting at my desk all day desperately trying to find the error in my code.
Picture of the print:
Here is my C Code. I am using MPLab and the HI-TECH C compiler :)
#include <pic.h>
//Variabler
int B = 0; //Definerer variablen B, used as a flag
int A = 0; //Definerer veriablen A, used as a flag
int E = 0;
int savedstatus = 1; //Definere variablen savedstatus used to check last status for input
int millicounter = 0; //Variabel to calculate seconds
int sec = 0; //Variabel holding seconds gone
int count = 0; //For counting seconds passed, used in input0 subroutine
int onesec = 0; //Used to counting seconds for blinking LED in input0 subroutine
int scount = 0;
//Variabler slut
void interrupt jesper(void)
{
T0IF = 0x00;
TMR0 = 96;
millicounter++;
if(millicounter == 20)
{
sec++;
millicounter = 0;
}
}
//Subrutines
void input0()
{
if(sec<=15 && E==0)
{
PORTA = 0x21;
}
else if(A==0)
{
scount = 0;
sec = 0;
count = sec;
A = 1;
E = 1;
}
else if(sec<=600 && sec>count)
{
count++;
if((scount+5)>=count)
{
if(B==0)
{
onesec = sec;
B = 1;
PORTA = 0x01;
}
else if(sec>onesec)
{
PORTA = 0x00;
B = 0;
scount = count;
scount;
}
else
{
PORTA = 0x01;
}
}
else
{
PORTA = 0x00;
}
}
else PORTA = 0x00;
}
void input1()
{
if(sec<=600)
{
PORTA = 0x20;
}
else
{
PORTA = 0x00;
}
}
//Subrutines over
int main(void)
{
TRISA = 0x00; //Sets all A-PORTS to output
TRISB = 0x01; //Sets all PORTB to output with the exception of BIT0
TRISC = 0x00; //Sets All PORTC to output
ANSEL = 0x00; //Disable Analog ports
ANSELH = 0x00; //Disable Analog ports
//Timer Config
PSA = 0x00;
PS0 = 0x01;
PS1 = 0x01;
PS2 = 0x01;
TMR0 = 0x60;
GIE = 0x01;
T0IE = 0x01;
T0IF = 0x00;
T0CS = 0x00;
//Timer Config Over
while(0x01)
{
if(savedstatus != RB0)
{
savedstatus = RB0;
sec = 0;
E = 0;
A = 0;
}
if(savedstatus == 1)
{
input1();
}
else
{
input0();
}
}
}
I really hope that you can help me here :)
Here is my flowchart for the subroutine input0 where my problem is. Btw some of my variables have different names in the code itself, but it shouldn't be hard to see.
Your main() calls input0() as often as possible. When input0() is in the flashing state it uses the conditional sec > count. I suspect that your intention is that input0() should only change the LED state at intervals of a second. But then on the else side of that conditional you turn both LEDs off. This else side is executing many times because main() is calling input0() so often. Try deleting the else condition where you turn the LEDs off.
void input0()
{
<snip>
else if(sec<=600 && sec>count)
{
<snip>
}
else PORTA = 0x00; // <-- delete this line so you're not always turning the LED off
}
I have a small task to program the following using C, for an ATmega48 controller:
In the beginning, all (6) LEDs are turned on.
When button SW1 is pressed, LEDs are only allowed to be turned off with the respective buttons.
When button SW2 is pressed, LEDs are only allowed to be turned on with the respective buttons.
Here is what I came up with:
#define F_CPU 1000000UL
#include <asf.h>
#include <util/delay.h>
volatile unsigned char r,d;
ISR(INT0_vect)
{
if (d = 0)
{
PORTB = PORTB | 1<<1;
d = 1;
}
else
{
PORTB = PORTB | 0<<2;
d = 0;
}
}
int main (void)
{
d = 0;
DDRC = 0x00;
PORTC = 0xFF;
DDRB= 0xFF;
PORTB = 0x00;
PCICR = 0b00000001;
sei();
while(1)
{
PCMSK0 = 0b00000100;
while (d == 0)
{
for (int i=0; i<6; i++)
{
if(!(PINC & (1<<i)))
PORTB = PORTB | i<<1;
}
}
PCMSK0 = 0b00000010;
while (d == 1)
{
for (int i=0; i<6; i++)
{
if(!(PINC & (1<<i)))
PORTB = PORTB | i<<0;
r = r<<1;
}
}
}
}
When I tried to simulate in Atmel AVR Studio, wrong LEDs were turning on when I pressed the respective buttons (e.g. LED2 for SW4), and interrupts never happened.
Please explain what I've done wrong, as I have already scoured several resources, and each one gives a different approach, which I fail to comprehend.
Though since you have not initialied interrupts in a proper way, These lines of code here which are not being executed at all, have two issues.
if (d = 0)
{
PORTB = PORTB | 1<<1;
d = 1;
}
else
{
PORTB = PORTB | 0<<2;
d = 0;
}
One issue that is clearly visible is: if (d = 0) does not check if d is equal to 0, instead it assigns 0 to d every single time.
Are you trying to set and clear the pins?
If yes, this is not the way it is supposed to be done.
Usually in Embedded we set the pins this way: PORTB |= (1<<1); //you have got this right
and clear the pins by PORTB &= ~(1<<1);
You stated that interrupts never happened. It is then a valid conclusion that d remains 0 all the time and you loop in while (d == 0) {} all the time. So r is never modified unless from elsewhere/apart from the code you have shown. Does this r have any implementation related to GPIO for LEDs? If Yes, then you have to first fix the issues in interrupts.
The reason behind interrupts never happened is that you have not initialized the External interrupts at all.
You need to configure EICRA – External interrupt control register A register.
Then you need to configure the EIMSK – External interrupt mask register
Then you need to configure the EIFR – External interrupt flag register
Reading the datasheet always helps to understand the implementation details.