I want to drive BlDC motor using L6234 Driver IC with help of Atmega 16 Controller. Logics for driving motor are given in the motor driver IC L6234 datasheet on page 9. Here is the link for datasheet. So, according to the datasheet I write a code to drive my motor. Here is my code:-
#define F_CPU 8000000UL
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#define hall1 (PINC & 1<<1) // connect hall sensor1
#define hall2 (PINC & 1<<2) //connect hall sensor2
#define hall3 (PINC & 1<<3) //connect hall sensor3
void main()
{
DDRC=0XF0;
DDRB=0XFF; //output as In1=PB.0 ,In2=PB.1, In3=PB.2, En0=PB.3 ,En1=PB.4, En3=PB.5
while(1)
{
if((hall3==4)&(hall2==0)&(hall1==1)) // step1
{
PORTB=0X19;
}
if((hall3==0)&(hall2==0)&(hall1==1)) // step2
{
PORTB=0X29;
}
if((hall3==0)&(hall2==2)&(hall1==1)) // step3
{
PORTB=0X33;
}
if((hall3==0)&(hall2==2)&(hall1==0)) // step4
{
PORTB=0X1E;
}
if((hall3==4)&(hall2==2)&(hall1==0))// step5
{
PORTB=0X2E;
}
if((hall3==4)&(hall2==0)&(hall1==0))// step6
{
PORTB=0X34;
}
}
}
But when I run this code, my motor is not working. So, can any one tell me, where is the mistake in my code.
The format of your code makes it really hard to debug. Since you are already using macros, may I make some suggestions to make it easier to read?
You have #define hall3 (PINC & 1<<3), but then this value needs to be 4 or 0. Why not just use it as a boolean?
if(hall3 && etc) // note the double &&
Right away, this will fix one error. 1<<3 is 8 not 4, so none of the if statements will ever succeed as the code is currently written. (Eg., 1 is 1<<0, not 1<<1.)
The PORTB hard-coded outputs are really hard to decipher as well. I suggest using #defines to make this easier, too.
#define EN1 3
#define EN2 4
#define EN3 5
#define IN1 0
#define IN2 1
#define IN3 2
...
PORTB = 1<<EN1 | 1<<EN2 | 1<<IN1; // step 1
Related
I am driving a stepper motor successfully using the following freeware code:
/*
* Simple demo, should work with any driver board
*
* Connect STEP, DIR as indicated
*
* Copyright (C)2015-2017 Laurentiu Badea
*
* This file may be redistributed under the terms of the MIT license.
* A copy of this license has been included with this distribution in the file LICENSE.
*/
#include <Arduino.h>
#include "BasicStepperDriver.h"
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM 120
// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS 1
// All the wires needed for full functionality
#define DIR 4
#define STEP 3
//Uncomment line to use enable/disable functionality
//#define SLEEP 13
// 2-wire basic config, microstepping is hardwired on the driver
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);
//Uncomment line to use enable/disable functionality
//BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, SLEEP);
void setup() {
stepper.begin(RPM, MICROSTEPS);
// if using enable/disable on ENABLE pin (active LOW) instead of SLEEP uncomment next line
// stepper.setEnableActiveState(LOW);
}
void loop() {
// energize coils - the motor will hold position
// stepper.enable();
/*
* Moving motor one full revolution using the degree notation
*/
stepper.rotate(360);
/*
* Moving motor to original position using steps
*/
stepper.move(-MOTOR_STEPS*MICROSTEPS);
// pause and allow the motor to be moved by hand
// stepper.disable();
delay(5000);
}
However, I would like to drive two motors at a time using the same Arduino-Uno and change the code a bit. What can I do? I am super new to coding so go easy. I understand there is something called a function and that it receives values. However, I need it to use multiple control pins: two for each motor - "step" (that moves the motor one step further each time) and "dir" (for each motor's rotation direction). I also understand that the function:
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);
cannot accept 4 values (of DIR1, DIR2, STEP1 and STEP2) at a time. I would like to make it possible to use the above code (with slight changes) in order to control 2 motors at a time using 4 different I/O pins (2 for the first motor driver's (my arduino is connected to a motor driver which I have 2 of and want to use the other to drive another motor) "step" and "dir" pins, and 2 for the 2nd motor driver's "step" and "dir" pins).
Thanx
I did the following and it worked!
/*
* Simple demo, should work with any driver board
*
* Connect STEP, DIR as indicated
*
* Copyright (C)2015-2017 Laurentiu Badea
*
* This file may be redistributed under the terms of the MIT license.
* A copy of this license has been included with this distribution in the file LICENSE.
*/
#include <Arduino.h>
#include "BasicStepperDriver.h"
// Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define MOTOR_STEPS 200
#define RPM1 60
#define RPM2 60
#define RPM3 60
// Since microstepping is set externally, make sure this matches the selected mode
// If it doesn't, the motor will move at a different RPM than chosen
// 1=full step, 2=half step etc.
#define MICROSTEPS1 4
#define MICROSTEPS2 4
#define MICROSTEPS3 4
// All the wires needed for full functionality
#define DIR1 3
#define STEP1 4
#define DIR2 5
#define STEP2 6
#define DIR3 7
#define STEP3 8
//Uncomment line to use enable/disable functionality
//#define SLEEPx 13
// 2-wire basic config, microstepping is hardwired on the driver
// BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP);
BasicStepperDriver stepper1(MOTOR_STEPS, DIR1, STEP1); //DIR1 = ,GPIO 3, STEP1 = GPIO 4
BasicStepperDriver stepper2(MOTOR_STEPS, DIR2, STEP2); //DIR2 = ,GPIO 5, STEP2 = GPIO 6
BasicStepperDriver stepper3(MOTOR_STEPS, DIR3, STEP3); //DIR3 = ,GPIO 7, STEP8 = GPIO 8
//Uncomment line to use enable/disable functionality
//BasicStepperDriver stepper(MOTOR_STEPS, DIRx, STEPx, SLEEPx);
void setup() {
stepper1.begin(RPM1, MICROSTEPS1);
stepper2.begin(RPM2, MICROSTEPS2);
stepper3.begin(RPM3, MICROSTEPS3);
// if using enable/disable on ENABLE pin (active LOW) instead of SLEEP uncomment next line
// stepper.setEnableActiveState(LOW);
}
void loop() {
// energize coils - the motor will hold position
// stepper.enable();
/*
* Moving motor one full revolution using the degree notation
*/
stepper1.rotate(360);
stepper2.rotate(360);
stepper3.rotate(360);
/*
* Moving motor to original position using steps
*/
stepper1.move(-MOTOR_STEPS*MICROSTEPS1);
stepper2.move(-MOTOR_STEPS*MICROSTEPS2);
stepper2.move(-MOTOR_STEPS*MICROSTEPS3);
// pause and allow the motor to be moved by hand
// stepper.disable();
delay(1000);
}
I'm trying to simply get an analog reading from A0 on my arduino Pro mini, but I cannot get the values stored in the adc register.
What is supposed to happen is the analog signal will be put in registers ADCL & ADCH and then the ADC interrupt will trigger.
I have a voltage divider set up on A0 that should just read 2.5V but my interrupt is not triggering and i cannot get values from ADCH or ADCL. I could get a reading in arduino so I know the hardware works. when i run this program i get a continuous print of 0 to my terminal which tells me the values of low and high never change as they should in the interrupt.
Here is my code:
# define F_CPU 16000000L
#include "time.h"
#include <avr/io.h>
#include <math.h>
#include <util/delay.h> // including the avr delay lib
#include <util/delay.h> // Including the avr delay lib
#include "usart.h"
#include "usart.cpp"
#include <stdio.h>
#include <avr/interrupt.h>
uint8_t low,high;
int main(void)
{
TCCR0B = (1<<CS02) | (1<<CS00);
USART_Init(MYUBRR);
DDRC = 0x0 ;
ADCSRA = (1<<ADEN) | (0<<ADIF); //activate adc & clear ADIF
ADMUX = (0<<ADLAR); //keep right adjusted
ADMUX = (1<<REFS0) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);//set ref as vcc, input as 0
ADCSRA = (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);//enable adc interrupt & divide clock by 124
DIDR0 = (0<<ADC0D);
sei();
ADCSRA = (1<<ADSC);//begin conversion
while (1)
{
while(ADSC==1)//wait for conversion to complete
{
sei();
}
USART_Send_int(low);
USART_Send_int(high);
_delay_ms(100);
ADCSRA = (1<<ADSC);
}
}
ISR(ADC_vect) //interrupt to trigger when conversion is complete
{
low = ADCL;
high = ADCH;
//ADCSRA = (1<<ADSC);
}
You should declare low and high as volatile since you are accessing them from an interrupt and the main loop:
volatile uint8_t low;
volatile uint8_t high;
Otherwise, the compiler is free to optimize your loop by moving the readings of those variables to be before the loop.
Alternatively, you could try putting a memory barrier in your loop, but that is the less-traveled road: most embedded developers tend to just use volatile.
I didn't test your code so there might still be other errors.
To debug this further, you should try putting low = 44; and high += 1; in your interrupt just to make sure the interrupt is running.
I'm having a strange problem that I hope someone can help with. My sketch works perfectly when uploaded to my UNO, but when I unplug it and plug it back in, it doesn't work correctly. If I re-upload it, it works again until power is cycled.
Once uploaded, the LCD reads:
Ferm:73.4 73/75
Room:75.1 75/75
After cycling power:
Ferm:73.45 73/18
Room:74.83 75/18
So after cycling power, I now get 2 decimal places and the "high" temp is stuck at "18".
/*
The circuit:
* 5V to Arduino 5V pin
* GND to Arduino GND pin
* CLK to Analog #5
* DAT to Analog #4
*/
// include the library code:
#include "Wire.h"
#include "Adafruit_LiquidCrystal.h"
#include <OneWire.h>
#include <DallasTemperature.h>
//variables for temp readings
float fermTemp;
float fermTempL=100;
float fermTempH=5;
float roomTemp;
float roomTempL=100;
float roomTempH=5;
// set OneWire bus to digital PIN 4 on the Arduino
#define ONE_WIRE_BUS 4
// Setup OneWire instance
OneWire oneWire(ONE_WIRE_BUS);
// Pass oneWire reference to Dallas Temp
DallasTemperature sensors(&oneWire);
// Connect via i2c, default address #0 (A0-A2 not jumpered)
Adafruit_LiquidCrystal lcd(0);
void setup()
{
// set up the LCD's number of rows and columns:
lcd.begin(16, 2);
// turn on backlight
lcd.setBacklight(HIGH);
}
void loop() {
readtemp();
LCDPrint();
}
void readtemp()
{
// get data from sensors
sensors.requestTemperatures();
fermTemp = (sensors.getTempFByIndex(0));
roomTemp = (sensors.getTempFByIndex(1));
// check/set High and Low temp
if (fermTemp<fermTempL) {
fermTempL=fermTemp;
}
if (fermTemp>fermTempH) {
fermTempH=fermTemp;
}
if (roomTemp<roomTempL) {
roomTempL=roomTemp;
}
if (roomTemp>roomTempH) {
roomTempH=roomTemp;
}
}
void LCDPrint()
{
lcd.setCursor(0,0);
lcd.print("Ferm:");
lcd.print(fermTemp,1);
lcd.setCursor(11,0);
lcd.print(fermTempL,0);
lcd.print("/");
lcd.print(fermTempH,0);
lcd.setCursor(0,1);
lcd.print("Room:");
lcd.print(roomTemp,1);
lcd.setCursor(11,1);
lcd.print(roomTempL,0);
lcd.print("/");
lcd.print(roomTempH,0);
}
I counted your characters, 16 per line. If you have a 16X2 display, there might be characters printed beyond the screen. I suspect it was not really 18, but something larger, say 180 or 1800. That could have been a result of failed first attempt to read temperature. This reading is stuck with you as temp High. In your code, you should define a reasonable high temperature, such as 125. Don't update temp High if it is above the reasonable temperature.
To confirm it, print temp High to serial port and inspect the value.
I started out using the Uno and I was able to get an interrupt working from a rotary library I found online but when I moved the project to the Mega and tried changing it for the different pins it stops. I spent a few hours trying to figure out the interrupt pin on the mega from online sources and just can't find any good resource to explain the mega interrupt pins sufficiently.
I am trying to use interrupts like so.
Rotary r = Rotary(10,11);
void setup(){
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT4) | (1 << PCINT5);
sei();
}
ISR(PCINT0_vect){
//stuff
}
It doesnt really matter what pin I am using for the interrupt if someone has a preferred method. I just need it to work.
Arduino interrupts are described here. It is easier to use than the example code you provide.
//Mega2560
// external interrupt int.0 int.1 int.2 int.3 int.4 int.5
// pin 2 3 21 20 19 18
void setup()
{
// interrupt # 0, pin 2
attachInterrupt(0, myISR, CHANGE); // Also LOW, RISING, FALLING
}
void loop()
{
}
void myISR() // must return void and take no arguments
{
// stuff
}
You don't need to enable interrupts with sei();, because attachInterrupt() does it for you. But you can disable interrupts with cli(); and re-enable them with sei();
I have hit a problem that I see no reason for it to be there.
The basic idea is to write to an SD card using the SdFat library in Arduino to log data.
Between logging the device will go to sleep and using a MOSFET I will switch off the SD card completely to save power.
The whole code works but only when I read the data from the file that I just wrote to.
When I take out the code to read from the file it creates the file but does not write to it at all.
For now I am using a delay instead of making the micro sleep just to reduce the things to focus on.
Here is the code that works with the reading the file, using the example file just to get this thing working for now.
const int chipSelect = 4;
/*
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
*/
#include <SdFat.h>
SdFat sd;
SdFile myFile;
char fileName[] = "2468.txt";
int sdPower = 3;
void setup()
{
pinMode(sdPower,OUTPUT);
}
void loop()
{
digitalWrite(sdPower,HIGH);
sd.begin(chipSelect, SPI_HALF_SPEED);
myFile.open(fileName, O_RDWR | O_CREAT | O_AT_END);
myFile.println("Hello World");
myFile.close();
// re-open the file for reading:
if (!myFile.open(fileName, O_READ)) {
sd.errorHalt("opening test.txt for read failed");
}
// read from the file until there's nothing else in it:
int data;
while ((data = myFile.read()) >= 0) Serial.write(data);
// close the file:
myFile.close();
digitalWrite(sdPower,LOW);
delay(1000);
}
The above works but the moment I take the last few lines out that do the reading it does not write to the file, like this.
const int chipSelect = 4;
/*
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
*/
#include <SdFat.h>
SdFat sd;
SdFile myFile;
char fileName[] = "2468.txt";
int sdPower = 3;
void setup()
{
pinMode(sdPower,OUTPUT);
}
void loop()
{
digitalWrite(3,HIGH);
sd.begin(chipSelect, SPI_HALF_SPEED);
myFile.open(fileName, O_RDWR | O_CREAT | O_AT_END);
myFile.println("Hello World");
myFile.close();
digitalWrite(3,LOW);
delay(1000);
}
Yet it still creates the file.
This is really confusing me.
Why does the program not write when it has the read section removed? surly because I am closing the file in both instances it should not matter ?
I know this is old but I was on the same situation, so I will write my answer to help anyone else who seeks for this.
The solution is simple, you must flush() the content before closing the file:
myFile.println("Hello World");
myFile.flush();
myFile.close();
This will ensure the content is written to the SD card.
Maybe the power to the card is being removed
{
digitalWrite(3,LOW);
}
before the directory and FAT data had been written do the card by the close() command. Try a 1 second delay delay before turning the card off. The reading data loop in the working example assures the file has been closed properly ;-)