I'm trying to run this code on TIVA C board. sw2 connected to PF0, sw1 connected to PF4 and RGB LED connected to PF1, PF2 and PF3.
When I press sw2 it shall turn the led blue and if sw1 is pressed it shall turn the led green otherwise it shall be red.
The code doesn't function properly. I hope you can point out what I did wrong.
/*************************
PORT F Addresses
*************************/
#define RCGCGPIO (*((volatile unsigned long*)0x400FE608)) //CLOCK
#define PORTFDATA (*((volatile unsigned long*)0x400253FC)) //DATA
#define PORTFDIR (*((volatile unsigned long*)0x40025400)) //DIRECTION
#define PORTFDEN (*((volatile unsigned long*)0x4002551C)) //ENABLE
#define PORTFLOCK (*((volatile unsigned long*)0x40025520)) //LOCK (lock or unlocks PF0)
#define PORTFCR (*((volatile unsigned long*)0x40025524)) //COMMIT (uncommit PF0)
#define PORTFPUR (*((volatile unsigned long*)0x40025510)) // PULL UP resistor
#define PORTFPDR (*((volatile unsigned long*)0x40025514)) // PULL Down resistor
/*************************/
int sw1;
int sw2;
int delay;
int main (void)
{
RCGCGPIO = 0x20; //Enable clock for PORT F
delay = RCGCGPIO;
PORTFLOCK = 0x4C4F434B; // unlock commit reg
PORTFCR = 0x01; // unlock PF0
PORTFDEN = 0x1F; //Enable pins 0 to 4
PORTFDIR = 0x0E; // pins 0 and 4 input - pins 1,2,3 output
PORTFPUR = 0x11;
while (1)
{
sw2 = PORTFDATA & 0x00000001;
sw1 = PORTFDATA & 0x00000010;
if (sw1 == 1)
PORTFDATA |= 0x00000002;
else if (sw2 == 1)
PORTFDATA |= 0x00000004;
else
PORTFDATA |= 0x00000008;
}
}
Here are two obvious problems with your code. There are probably more...
You set sw1 = PORTFDATA & 0x00000010, so the only possible values sw1 can have are 0x10 or 0x00. Then you test if (sw1 == 1). But this test will never be true because sw1 can never equal 1.
You use the |= operator to set the bits of PORTFDATA. But nowhere do you ever clear the bits of PORTFDATA. So your LEDs may turn on but they will never turn off.
Have you tried the sample code comming with CCS to make sure that hardware are functional?
The sample code uses TI library instead of plain register Read & Write, however you can dig out the acutal register by go to defination. Anyway, I'm a bit curious about why you use plain register in the first place instead of TI library? ARM MCU is not 8051 anymore.
A couple of things to keep in mind:
The launchpad buttons are negative logic, so if your switch1== 0x01, it is NOT being pressed.
Try something like:
If
sw1 == 0x01 //switch not pressed
PORTFDATA &= ~(0x0E); //ledz off
else
PORTFDATA ^= 0x02; //toggle red
I am also learning ARM & C solely self-study, so I feel your pain. It took many hours of toggling single leds with bitwise operators just to fathom what is going on. Stick with it!!!
/e
Related
I have a custom board with device LPC1768. While every other functionalities (such as LCD on SPI, Ethernet, I2C EEPROM, etc.) are OK,
for some reason, while I can turn ON and OFF LEDs on the GPIO2 but I can't do the same for the pins on the GPIO1. Maybe I shouldn't blame whole GPIO1 (or myself) but at least the part I try to use.
If I connect a button on one of the the GPIO1 pins (with internal pull-ups and as an OUTPUT)
I can read the button inputs as it should be.
Here is the definition part as per the user manual;
#define FIO_BASE_ADDR (0x2009C000)
#define FIO1CLR (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x3C))
#define FIO2CLR (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x5C))
#define FIO1SET (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x38))
#define FIO2SET (*(volatile unsigned int *)(FIO_BASE_ADDR + 0x58))
While a LED on the pin P2.5 turns ON and OFF as it should be;
FIO2SET = (1uL << 5); // P2.5
FIO2CLR = (1uL << 5); // P2.5
A LED on P1.18 doesn't turn ON;
FIO1SET = (1uL << 18); // P1.18
In order to test all the LEDs connected to the GPIO1 pins, I wrote two lines of code using LPC17xx.h and then proofed that it works, all the LEDs are turning ON and OFF accordingly.
LPC_GPIO1->FIOSET = 0xffffffff;
LPC_GPIO1->FIOCLR = 0xffffffff;
Any input highly appreciated.
Im trying to build a program that has a scannerlight with at least 5 leds and one button connected to an external interrupt pin. A single button press (and release) to start the scanner light. Pressing (and releasing) stops the scanner light again (and so on...).
I have a ground side switch on PD2
i have my LEDS on pin PD3,PD4,PD5,PD6 and PD7.
Im useing ATMega328P
I know my towering light works when i press on the button the towering light stops but when i press again it feels like it doesnt return the value to 1.
My code:
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define BIT_IS_CLEAR(byte, bit) (!(byte & (1 << bit)))
volatile int value = 1;
int main(void)
{
DDRD = 0b111110000;
DDRD &= ~(1 << PD2); // clear DDRD bit 2, sets PD2 (pin 4) for input
PORTD |= (1 << PD2); // set PD2/INT0 (pin 4) internal pull-up resistor
PCICR = 0b00000100;
PCMSK2 = 0b00000100;
sei();
while (value==1) //when value is 1 it should start having a towerlight
{
PORTD= 0x80;
_delay_ms(15000);
PORTD= 0x40;
_delay_ms(15000);
PORTD= 0x20;
_delay_ms(15000);
PORTD= 0x10;
_delay_ms(15000);
PORTD= 0x08;
_delay_ms(15000);
}
}
ISR(PCINT2_vect)
{
if(BIT_IS_CLEAR(PIND, PD2) & value==1) { // if switch is pressed (logic low)
value=0;
} else if(value == 0) {
value=1;
} else {
// ideally should never get here, but may occasionally due to timing
}
}```
regarding:
while (value==1)
{
....
}
When value is 0 the loop is exited, execution then exits the program. This is a serious logic flaw in the program
You are using a bitwise AND where it should be a logical AND. Change this
if(BIT_IS_CLEAR(PIND, PD2) & value==1)
to this
if(BIT_IS_CLEAR(PIND, PD2) && (0 != value))
Comparing for non-zero as opposed to equal to 1 guards against value being corrupted; since you want a zero or non-zero condition. Adding brackets makes the intention very clear. Yoda comparisons (putting the constant on the left hand side) prevents accidental assignment.
One other thing to consider is what you're doing to debounce the switch - in an analogue fashion with R-C+Schmitt or monostable, or in a digital fashion where you have a timer routine that samples the input every so often and counts "how many 1s or 0s over the last, say, 16 samples"?
I find that edge triggered interrupts don't work particularly well for manual switch inputs.
I am new to AVR programming, so sorry if question is trivial.
Using :
OS : Windows7
IDE : Atmel studio
uC = m328p
Pins:
ADC signal - ADC0/PC0
LED_values - (PB0 - PB7)
LED_START - PD1
LED_LIGHT - PD0
BUTTON - PD2
Goal: When you press the button it turns On the LED_START and it needs to start with conversion.
AVR gets interrupt and starts ADC conversion. Basically program has two interrupts. I know that INT0 interrupt has highest priority.
I dont know how to deal with them.
I have tried several things like adding global variable "start" and changing it. And also when i only set LED START it turns On and it stays in that state until LED_values reach certain value, then LED START turns Off by it self.
So please can you show me how to handle two interrupts so that fulfills stated goal and explain me what im doing wrong.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
#define BIT_IS_SET(byte, bit) (byte & (1 << bit))
#define BIT_IS_CLEAR(byte, bit) (!(byte & (1 << bit)))
typedef enum{false, true} bool;
bool previousState = false;
bool start = false;
char num;
void setup();
void loop();
void ADC_init();
void EI_init(); // External Interrupt
int main(void)
{
setup();
loop();
}
void setup(){
DDRC &= ~(0x1); // LDR Input
DDRB = 0xFF; //LEDs value Output
DDRD |= 0x3; //LED light LED start Output
DDRD &= ~(1 << PIND2); //Button Input
}
void loop(){
PORTD |= (1 << PIND2);
EI_init();
ADC_init();
sei();
if(start){
ADCSRA |= (1 << ADSC);
}
while(1){}
}
void ADC_init(){
ADMUX = 0x60;
ADCSRA = 0x8B;
ADCSRB = 0x0;
ADCH = 0x0;
}
ISR(ADC_vect) {
PORTB = ADCH; // assign contents of ADC high register to Port D pins
int b = (int)ADCH;
if(b > 180) { //100
PORTD = 0x1;
}else{
PORTD &= ~(0x1);
}
_delay_ms(100);
ADCSRA |= (1 << ADSC); // start next ADC
}
void EI_init(){
EIMSK |= (1 << INT0); // Interrupt enabled
EICRA |= (1 << ISC00); // any state change
}
ISR(INT0_vect){
if(BIT_IS_CLEAR(PORTD,PIND2)){
start = true;
}else{
start = false;
}
}
Here is scheme : scheme
First of all, you should make start be volatile since it is being used by both the main loop and the interrupt. The volatile keyword tells the compiler that the variable might be modified by things outside of its control, so it cannot optimize away any reads or writes to the variable:
volatile bool start = false;
Secondly, you probably want to remove this line you wrote at the end of loop:
while(1){}
That line is bad because it causes your program to go into an infinite loop where it does nothing. I think you actually want the code you wrote about it in the loop function to run multiple times.
Secondly, after you detect that the start flag has been set, you probably need to set it to 0, or else it will just be 1 forever.
Third, setting start to false in the INT0 ISR might be a bad idea, because it might get set to false before you main loop has a chance to observe it being true and handle the event. I guess it really depends on exactly what you are trying to do. You could try adding details to your question about exactly what problem you are trying to solve using the AVR. See What is the XY problem?.
There are probably other issues with your code that need to be debugged. Can you think of any ways to make this simpler? Maybe you can reduce the number of interrupts you are using. To debug, you can try blinking some LEDs to figure out what parts of your program are executing.
I'm trying to read a value from an avr pin but it doesn't work.
I'm trying to read a value that is coming from a push button and this button is connected to 5V DC cell.
When I press the button the 5V should go to the atmega32 and reads it as 1, then the if statement becomes true and the led goes on.
However, when the value becomes true the led will turn on but its not.
bit 1 is the button
bit 0 is the led
Code
#define DDRA (*((volatile unsigned char *)0x3A))
#define PORTA (*((volatile unsigned char *)0x3B))
#define PINA (*((volatile unsigned char *)0x39))
int main(void) {
DDRA |= 0b00000001; // pin 0 output
while (1) {
if ((PINA&0b00000010) == 1) { // button pressed
PORTA |= 0b00000001; // turn led on
}
}
}
I find one logic error here:
if ((PINA&0b00000010) == 1) // button pressed
when the bit 1 is set, (PINA&0b00000010) == 2.
Normally, when you do bit check, just do this:
if (PINA&0b00000010) // button pressed
Just to make sure, your button has to have a pull-up / pull-down resistor connected to ground. Without it, you can't correctly read whether the pin is on or off.
https://learn.sparkfun.com/tutorials/pull-up-resistors
You should change your hardware setup, and make your button active low, which means that pushing the button connects your GPIO pin to ground. Instead of connecting your button to positive side of the 5V cell, connected it to the negative side. That will let you take advantage of the internal pull resistor that you can active on your GPIO. Once you do that, your code should be changed to look something like this:
#define DDRA (*((volatile unsigned char *)0x3A))
#define PORTA (*((volatile unsigned char *)0x3B))
#define PINA (*((volatile unsigned char *)0x39))
#define LED_BIT 0
#define BTN_BIT 1
int main(void)
{
DDRA = (1 << LED_BIT); // PA0 output
PORTA = (1 << BTN_BIT); // enable internal pull up on PA1
while (1) {
if (!(PINA & (1 << BTN_BIT))) { // button pressed
PORTA |= (1 << LED_BIT); // turn led on
}
}
}
Notice that the if statement now checks to see if the PA1 is a 0 because the button is set up to connect to ground when it is pushed. Also notice that there is a new line in there that enables an internal pull-up, which makes PA1 read a 1 while the button is not pressed. If you don't change your button an active low configuration, you will have to use an external pull-down resistor in order for your code to work correctly.
I am trying to create a C program which receives a char via UART, "prints" the correspondent binary by turning on 8 leds in my breadboard and send the char back to the transmitter.
Here is the code I am using:
//CPU clock
#define F_CPU 1000000UL
//Baud
#define BAUD 9600
//Baud rate
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
#include <avr/io.h>
#include <util/delay.h>
#include <util/setbaud.h>
#include <avr/interrupt.h>
#include <stdint.h>
//Communication Parameters:
//8 bits of data
//1 bit stop
//No parity
void uart_init(void){
//Bit 7 - RXCIEn: RX complete interrupt enable
//Bit 6 - TXCIEn: TX complete interrupt enable
//Bit 5 - UDRIE: USART data register empty interrupt enable
//Bit 4 - RXENn: Receiver enable
//Bit 3 - TXENn: Transmitter enable
UCSR0B = 0b10011000;
//Bit 7 - RXCn: USART receive complete.
//Bit 6 - TXCn: USART transmit complete
//Bit 5 - UDREn: USART data register empty
UCSR0A = 0b00000000;
//Bit 11:0 – UBRR11:0: USART baud rate register
//Whereas H are the higher bits and L the lower bits
//It comes from the setbaud.h
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
//Bit 7:6 - UMSELn1:0: USART mode select
//00 Asynchronous USART
//01 Synchronous USART
//11 Master SPI
//Bit 5:3 - Reserved bits in MSPI mode
//Bit 2 - UDORDn: Data order
//Bit 1 - UCPHAn: Clock phase
//Bit 0 - UCPOLn: Clock polarity
UCSR0C = 0b10000110;
}
// function to send data
void uart_transmit (uint8_t data)
{
while (!( UCSR0A & (1<<UDRE0))); // wait while register is free
UDR0 = data; // load data in the register
}
int main (void)
{
//Starts UART
uart_init();
//All led GPIOs as output
DDRB = 0xFF;
DDRC = 0x01;
//Enabling interrupts
sei();
while(1)
{
;
}
return 0;
}
ISR(USART_RX_vect)
{
//Variable to hold the incoming char
uint8_t received_bit = UDR0;
PORTC ^= 0x01;
PORTB = 0x00;
PORTB = received_bit;
uart_transmit(received_bit);
}
When I flash it to the chip and start using it, I get a weird behaviour.
I am sending a "U" which is a nice binary 01010101 to compare with.
However I am getting weird answers back from my chip:
My questions regarding UART under an ATMEGA168a are the following:
When setting the F_CPU am I supposed to stay with the 1MHZ used by the ATMEGA168a or do I have to use the one of my transmitter (Intel i7)? Could it be the problem?
When does the UDR0 gets "updated"? Whenever I hit the enter to send the character to chip via Terminal?
What could be generating this issue?
In the function uart_init() you set bits 7:6 to 10 which is a reserved state according to the ATMega 168A manual. To get the desired asynchronous UART functionality, set them to 00:
UCSR0C = 0b00000110;
The other reason why your example was not working was the baudrate settings, as explained in my comment below.
You already included the <util/setbaud.h> header file, which contains macros to make UART setup easier. Look here for the documentation. These macros take the input provided by you in F_CPU and BAUDRATE and calculate the settings for the UART configuration registers (UBRRH_VALUE and UBRRL_VALUE).
You used it almost correctly, however to take advantage of the UART baudrate doubling feature of the ATmega, add the following code after setting the UBRR0H/L value:
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
This sets or clears the U2X0 bit dependent on the calculations of the setbaud macros.
Also, I believe you can remove the line
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
because that's exactly what setbaud.h does.