AVR C - Atmega32上的步进电机和adc代码

时间:2016-08-29 20:17:28

标签: c embedded microcontroller avr atmega

我从微控制器开始,我正在尝试编写连接到Atmega32(带外部时钟)微控制器的太阳能电池板的电压测量。太阳能电池板安装在步进电机上,可以使太阳能电池板旋转。

这是我的代码的一部分(可编译):

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define B_0000  0
#define B_0001  1
#define B_0010  2
#define B_0011  3
#define B_0100  4
#define B_0101  5
#define B_0110  6
#define B_0111  7
#define B_1000  8
#define B_1001  9
#define B_1010  a
#define B_1011  b
#define B_1100  c
#define B_1101  d
#define B_1110  e
#define B_1111  f

#define _B2H(bits)  B_##bits
#define B2H(bits)   _B2H(bits)
#define _HEX(n)     0x##n
#define HEX(n)      _HEX(n)
#define _CCAT(a,b)  a##b
#define CCAT(a,b)   _CCAT(a,b)
#define BYTE(a,b)       HEX( CCAT(B2H(a),B2H(b)) )

#define STEPMOTOR_PORT PORTC
#define SOLAR_INPUT_PIN (1<<MUX2)|(1<<MUX0)

#define STEPMOTOR_STEP 8 // length of one step motor full step
#define STEPMOTOR_YZ_MAX_POSITION 6 // max stepmotor cw position
#define STEPMOTOR_YZ_MIN_POSITION -6 //max stepmotor ccw position

/* counterclockwise */
void inline stepmotor_yz_ccw_step()
{
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0000, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0001, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0011, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0010, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0110, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0100, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(1100, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(1000, 0000);  
    _delay_us(10000);

}

/* clockwise */
void inline stepmotor_yz_cw_step()
{
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(1000, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(1100, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0100, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0110, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0010, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0011, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0001, 0000);  
    _delay_us(10000);
    STEPMOTOR_PORT = BYTE(0000, 0000);  
    _delay_us(10000);
}

unsigned int inline measure_voltage()
{
    ADCSRA |= (1 << ADSC);  // Start conversion
    while (ADCSRA & (1 << ADSC)) ;  // wait for conversion to complete
    return ADCW;
}

void inline ports_init()
{
    DDRD = BYTE(1111, 1111);
    DDRC = BYTE(1111, 1111);
    PORTD = BYTE(1111, 1111);
    PORTC = BYTE(0000, 0000);
}

/* single measurement, ref voltage is 5V, division factor 32, PA5 port */
void inline adc_init()
{
    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0);
    ADMUX = SOLAR_INPUT_PIN;
    ADMUX |= (1 << REFS0);
}

/* light led according to measured voltage */
void inline light_leds(unsigned int voltage)
{
    if (voltage < 128) {
        PORTD = BYTE(1111, 1110);
    }
    if (voltage > 128 && voltage < 256) {
        PORTD = BYTE(1111, 1101);
    }
    if (voltage > 256 && voltage < 384) {
        PORTD = BYTE(1111, 1011);
    }
    if (voltage > 384 && voltage < 512) {
        PORTD = BYTE(1111, 0111);
    }
    if (voltage > 512 && voltage < 640) {
        PORTD = BYTE(1110, 1111);
    }
    if (voltage > 640 && voltage < 768) {
        PORTD = BYTE(1101, 1111);
    }
    if (voltage > 768 && voltage < 896) {
        PORTD = BYTE(1011, 1111);
    }
    if (voltage > 896 && voltage < 1024) {
        PORTD = BYTE(0111, 1111);
    }
}

int main(void)
{
    unsigned int current_voltage = 0;
    unsigned int max_voltage = 0;
    int max_position = 0;
    int current_position = 0;
    int i = 0;
    ports_init();
    adc_init();

    while (1) {

            /* if not too far */
            if (current_position < STEPMOTOR_YZ_MAX_POSITION) {
                for (i = 0; i < STEPMOTOR_STEP; ++i)
                    stepmotor_yz_cw_step();

                current_position++;

            }
            _delay_ms(5000);

            current_voltage = measure_voltage();

            if (current_voltage > max_voltage)
            {
                max_voltage = current_voltage;
                max_position = current_position;
                light_leds(max_voltage);
            }       
    }
}

问题在于,电压测量和步进电机旋转分开工作。即使是两步电机的旋转也能工作。 ADC本身也可以点亮LED,如上面的最大电压,或者例如每次测量后的电流电压。但当我将这两者混合在一起时,一切都会停止。

当我像上面那样把它们放在一起时,我认为&#34;太远&#34;如果因为步进电机没有移动甚至没有检查,也没有发生电压测量。

当我将current_position设置为volatile时,步进电机会按预期开始旋转,但它永远不会停止,就像current_position根本没有增加一样。在那种情况下,adc测量不起作用。

Programator是FT232R Bitbang。

我正在使用这个stepmotor和驱动程序: http://www.instructables.com/id/BYJ48-Stepper-Motor/

太阳能电池板的电压为0-5V

我正在使用入门套件测试它(英文版可以通过页面顶部的图标打开): http://and-tech.pl/zestaw-evb-5-1/

生成文件:

F_CPU=16000000

CC=avr-gcc
CFLAGS=-mmcu=atmega32 -Wall -O2 -DF_CPU=$(F_CPU) -gstabs -ffunction-sections -fdata-sections

CXX=avr-g++
CXXFLAGS=$(CFLAGS)

OBJCOPY=avr-objcopy
AVRDUDE = -c ft232r -p m32 -P ft0 -B 19200 -U flash:w:"program.hex":a 

program:  main.o
    $(CXX) -o program main.o -I.

main.o: main.c 
    $(CXX) $(CXXFLAGS) -c main.c -I. 

hex: program
    $(OBJCOPY) -O ihex program program.hex

upload: hex
    avrdude $(AVRDUDE)

clean:
    rm -f *.hex *.o *.s *.hex 

我想这是一个代码问题,而不是硬件,因为我在两个不同的Atmega32微控制器上测试它,以确保一切正常。

提前感谢您的帮助!

Br,ruker

0 个答案:

没有答案