久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 822|回復: 11
打印 上一主題 下一主題
收起左側

我這個程序的電機只會震動不會轉,是哪里出了問題啊。

[復制鏈接]
跳轉到指定樓層
樓主
步進電機用的是5V的28BYJ48,是4相5線的,驅動板是ULN2003。
#include <STC12C5A60S2.H>
#include <intrins.h>
#include <math.h>
#include <stdio.h>

// 定義IO口
sbit LCD_RS = P1^0;
sbit LCD_RW = P1^1;
sbit LCD_EN = P1^2;
sbit LCD_D0 = P2^0;
sbit LCD_D1 = P2^1;
sbit LCD_D2 = P2^2;
sbit LCD_D3 = P2^3;
sbit LCD_D4 = P2^4;
sbit LCD_D5 = P2^5;
sbit LCD_D6 = P2^6;
sbit LCD_D7 = P2^7;

sbit DS1302_CLK = P3^4;
sbit DS1302_IO  = P3^5;
sbit DS1302_RST = P3^6;

sbit BTN_MODE = P3^0;
sbit BTN_UP   = P3^1;
sbit BTN_DOWN = P3^2;
sbit BTN_LEFT = P3^3;
sbit BTN_RIGHT= P3^7;

// 定義步進電機IO口,假設連接到P0口
sbit IN1 = P0^0;
sbit IN2 = P0^1;
sbit IN3 = P0^2;
sbit IN4 = P0^3;
sbit IN5 = P0^4;
sbit IN6 = P0^5;
sbit IN7 = P0^6;
sbit IN8 = P0^7;

// 全局變量
unsigned char mode = 0; // 0: 自動模式, 1: 手動模式
float current_altitude = 0.0; // 當前高度角
float current_azimuth = 0.0;  // 當前方位角
unsigned int auto_update_counter = 0; // 自動模式更新計數器


// 經緯度 (需要根據實際情況修改)
float latitude = 39.9;  // 北京的緯度
float longitude = 116.3; // 北京的經度

// DS1302 時鐘相關
unsigned char time[7] = {0}; // 秒,分,時,日,月,星期,年

// 步進電機相關
// unsigned char motor_step_table[] = {0x08, 0x0C, 0x04, 0x06, 0x02, 0x03, 0x01, 0x09}; // 步進電機步序,原始步序
unsigned char motor_step_table[] = {0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08}; // 步進電機步序, 嘗試的步序
int altitude_motor_step = 0;  // 高度角電機當前步數
int azimuth_motor_step = 0;   // 方位角電機當前步數
#define MOTOR_STEP_ANGLE 1.8 // 步進電機每步轉動的角度 (根據實際情況修改)

// 軟件限位 (根據實際情況修改)
#define MAX_ALTITUDE_STEPS 100 // 高度角最大步數, 對應最大角度 180 度
#define MAX_AZIMUTH_STEPS 200  // 方位角最大步數, 對應最大角度 360 度

// 函數聲明
void delay(unsigned int i);
void delay_us(unsigned int i);
void lcd_write_command(unsigned char command);
void lcd_write_data(unsigned char dat);
void lcd_init();
void lcd_clear();
void lcd_display_string(unsigned char x, unsigned char y, unsigned char *str);
void ds1302_write_byte(unsigned char dat);
unsigned char ds1302_read_byte();
void ds1302_write_time();
void ds1302_read_time();
void calculate_sun_position(float *altitude, float *azimuth);
void motor_rotate(unsigned char motor, int steps);
void update_motor_position();
unsigned char button_scan();

// 延時函數
void delay(unsigned int i) {
    while (i--);
}

void delay_us(unsigned int i) {
    while (i--) {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    }
}

// LCD12864 相關函數
void lcd_write_command(unsigned char command) {
    LCD_RS = 0;
    LCD_RW = 0;
    P2 = command;
    LCD_EN = 1;
    delay_us(5);
    LCD_EN = 0;
}

void lcd_write_data(unsigned char dat) {
    LCD_RS = 1;
    LCD_RW = 0;
    P2 = dat;
    LCD_EN = 1;
    delay_us(5);
    LCD_EN = 0;
}

void lcd_init() {
    lcd_write_command(0x30); // 基本指令集
    delay_us(100);
    lcd_write_command(0x30); // 基本指令集
    delay_us(37);
    lcd_write_command(0x0C); // 顯示開,光標關,閃爍關
    delay_us(100);
    lcd_write_command(0x01); // 清除顯示
    delay_us(10000);
    lcd_write_command(0x06); // 光標右移,AC+1
    delay_us(100);
}

void lcd_clear() {
    lcd_write_command(0x01); // 清除顯示
    delay(2);
}

void lcd_display_string(unsigned char x, unsigned char y, unsigned char *str) {
    if (y == 0) {
        lcd_write_command(0x80 + x); // 第一行
    } else {
        lcd_write_command(0x90 + x); // 第二行
    }
    while (*str) {
        lcd_write_data(*str++);
    }
}

// DS1302 相關函數
void ds1302_write_byte(unsigned char dat) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        DS1302_CLK = 0;
        DS1302_IO = dat & 0x01;
        DS1302_CLK = 1;
        dat >>= 1;
    }
}

unsigned char ds1302_read_byte() {
    unsigned char i, dat = 0;
    for (i = 0; i < 8; i++) {
        DS1302_CLK = 0;
        dat >>= 1;
        if (DS1302_IO) {
            dat |= 0x80;
        }
        DS1302_CLK = 1;
    }
    return dat;
}

void ds1302_write_time() {
    unsigned char i;
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    ds1302_write_byte(0x8E); // 控制命令, WP=0, 允許寫
    ds1302_write_byte(0x00); // 允許寫
    DS1302_RST = 0;

    DS1302_RST = 1;
    ds1302_write_byte(0xBE); // 突發模式寫
    for (i = 0; i < 7; i++) {
        ds1302_write_byte(time[i]);
    }
    DS1302_RST = 0;
}

void ds1302_read_time() {
    unsigned char i;
    DS1302_RST = 0;
    DS1302_CLK = 0;
    DS1302_RST = 1;
    ds1302_write_byte(0xBF); // 突發模式讀
    for (i = 0; i < 7; i++) {
        time[i] = ds1302_read_byte();
    }
    DS1302_RST = 0;
}

// 太陽位置計算 (時控法)
void calculate_sun_position(float *altitude, float *azimuth) {
    // 將時間轉換為小時 (UTC 時間)
    float hour = time[2] + time[1] / 60.0 + time[0] / 3600.0 - 8.0; // 轉換為UTC時間
    // 把所有變量聲明放在函數開頭
    int year, month, day;
    int A, B;
    long JD;
    float T, L, g, lambda, epsilon, delta, H, cos_azimuth;

    if (hour < 0) hour += 24.0;

    // 計算儒略日 (JD)
    year = 2000 + time[6]; // 年份
    month = time[4];       // 月份
    day = time[3];         // 日

    if (month <= 2) {
        year--;
        month += 12;
    }
    A = year / 100;
    B = 2 - A + A / 4;
    JD = (long)(365.25 * (year + 4716)) + (long)(30.6001 * (month + 1)) + day + B - 1524.5;

    // 計算儒略世紀數 (T)
    T = (JD - 2451545.0) / 36525.0;

    // 計算太陽的平黃經 (L)
    L = 280.46646 + 36000.76983 * T + 0.0003032 * T * T;
    L = fmod(L, 360.0); // 取模

    // 計算太陽的平近點角 (g)
    g = 357.52911 + 35999.05029 * T - 0.0001537 * T * T;
    g = fmod(g, 360.0);

    // 計算太陽的黃經 (lambda)
    lambda = L + 1.914602 * sin(g * 3.14159265 / 180.0) - 0.004817 * sin(2 * g * 3.14159265 / 180.0) - 0.019993 * T;
    lambda = fmod(lambda, 360.0);

    // 計算黃赤交角 (epsilon)
    epsilon = 23.439291 - 0.0130042 * T - 0.00000016 * T * T;

    // 計算太陽的赤緯 (delta)
    delta = asin(sin(epsilon * 3.14159265 / 180.0) * sin(lambda * 3.14159265 / 180.0)) * 180.0 / 3.14159265;

    // 計算時角 (H)
    H = (hour * 15.0) - 180.0 - longitude;
    H = fmod(H, 360.0);

    // 計算高度角 (altitude)
    *altitude = asin(sin(latitude * 3.14159265 / 180.0) * sin(delta * 3.14159265 / 180.0) +
                     cos(latitude * 3.14159265 / 180.0) * cos(delta * 3.14159265 / 180.0) * cos(H * 3.14159265 / 180.0)) * 180.0 / 3.14159265;

    // 計算方位角 (azimuth)
    cos_azimuth = (sin(delta * 3.14159265 / 180.0) - sin(*altitude * 3.14159265 / 180.0) * sin(latitude * 3.14159265 / 180.0)) /
                        (cos(*altitude * 3.14159265 / 180.0) * cos(latitude * 3.14159265 / 180.0));
    if (cos_azimuth > 1.0) cos_azimuth = 1.0;
    if (cos_azimuth < -1.0) cos_azimuth = -1.0;
    *azimuth = acos(cos_azimuth) * 180.0 / 3.14159265;

    if (H > 0) {
        *azimuth = 360.0 - *azimuth;
    }
}

// 步進電機控制 (簡化版, 用于調試)
void motor_rotate(unsigned char motor, int steps) {
    int i, direction;
    unsigned char motor_output;

    direction = (steps > 0) ? 1 : -1;
    steps = (steps > 0) ? steps : -steps;

    for (i = 0; i < steps; i++) {
        if (motor == 0) { // 高度角電機
            altitude_motor_step += direction;
            if (altitude_motor_step < 0) altitude_motor_step = 0;
            if (altitude_motor_step > MAX_ALTITUDE_STEPS) altitude_motor_step = MAX_ALTITUDE_STEPS;

            // 直接控制 IO (假設 A-AB-B-BC-C-CD-D-DA 相序)
            if (altitude_motor_step % 8 == 0) P0 = (P0 & 0xF0) | 0x08; // A
            if (altitude_motor_step % 8 == 1) P0 = (P0 & 0xF0) | 0x0C; // AB
            if (altitude_motor_step % 8 == 2) P0 = (P0 & 0xF0) | 0x04; // B
            if (altitude_motor_step % 8 == 3) P0 = (P0 & 0xF0) | 0x06; // BC
            if (altitude_motor_step % 8 == 4) P0 = (P0 & 0xF0) | 0x02; // C
            if (altitude_motor_step % 8 == 5) P0 = (P0 & 0xF0) | 0x03; // CD
            if (altitude_motor_step % 8 == 6) P0 = (P0 & 0xF0) | 0x01; // D
            if (altitude_motor_step % 8 == 7) P0 = (P0 & 0xF0) | 0x09; // DA

            delay(50); // 更長的延時, 便于觀察
        } else { // 方位角電機
            azimuth_motor_step += direction;
            if (azimuth_motor_step < 0) azimuth_motor_step = 0;
            if (azimuth_motor_step > MAX_AZIMUTH_STEPS) azimuth_motor_step = MAX_AZIMUTH_STEPS;

            // 直接控制 IO (假設 A-AB-B-BC-C-CD-D-DA 相序)
            if (azimuth_motor_step % 8 == 0) P0 = (P0 & 0x0F) | 0x90; // A
            if (azimuth_motor_step % 8 == 1) P0 = (P0 & 0x0F) | 0x10; // AB
            if (azimuth_motor_step % 8 == 2) P0 = (P0 & 0x0F) | 0x30; // B
            if (azimuth_motor_step % 8 == 3) P0 = (P0 & 0x0F) | 0x20; // BC
            if (azimuth_motor_step % 8 == 4) P0 = (P0 & 0x0F) | 0x60; // C
            if (azimuth_motor_step % 8 == 5) P0 = (P0 & 0x0F) | 0x40; // CD
            if (azimuth_motor_step % 8 == 6) P0 = (P0 & 0x0F) | 0xC0; // D
            if (azimuth_motor_step % 8 == 7) P0 = (P0 & 0x0F) | 0x80; // DA

            delay(50); //更長的延時, 便于觀察
        }
    }
}

// 更新電機位置
void update_motor_position() {
    int altitude_steps, azimuth_steps;
    float target_altitude, target_azimuth;

    if (mode == 0) { // 自動模式
        calculate_sun_position(&target_altitude, &target_azimuth);

        // 計算需要轉動的步數
        altitude_steps = (int)((target_altitude - current_altitude) / MOTOR_STEP_ANGLE);
        azimuth_steps = (int)((target_azimuth - current_azimuth) / MOTOR_STEP_ANGLE);

        // 更新當前角度
        current_altitude += altitude_steps * MOTOR_STEP_ANGLE;
        current_azimuth += azimuth_steps * MOTOR_STEP_ANGLE;

        // 驅動電機
        motor_rotate(0, altitude_steps); // 高度角電機
        motor_rotate(1, azimuth_steps); // 方位角電機
    }
}

// 按鈕掃描
unsigned char button_scan() {
    if (!BTN_MODE) {
        delay(20); // 消抖
        if (!BTN_MODE) {
            while (!BTN_MODE); // 等待釋放
            return 1; // 模式切換
        }
    }
    if (!BTN_UP) {
        delay(20);
        if (!BTN_UP) {
            while (!BTN_UP);
            return 2; // 上
        }
    }
    if (!BTN_DOWN) {
        delay(20);
        if (!BTN_DOWN) {
            while (!BTN_DOWN);
            return 3; // 下
        }
    }
    if (!BTN_LEFT) {
        delay(20);
        if (!BTN_LEFT) {
            while (!BTN_LEFT);
            return 4; // 左
        }
    }
    if (!BTN_RIGHT) {
        delay(20);
        if (!BTN_RIGHT) {
            while (!BTN_RIGHT);
            return 5; // 右
        }
    }
    return 0; // 無按鈕按下
}

// 重新實現 _putchar 函數,輸出到 LCD (注意是 _putchar)
char _putchar(char c) {
    lcd_write_data(c); // 使用你的 LCD 數據寫入函數
    return c;
}

void main() {
    unsigned char btn_value;
    unsigned char display_str[17];
    float displayed_altitude, displayed_azimuth; // 用于顯示的限幅后的角度

    lcd_init();
    lcd_clear();

    // 設置初始時間 (根據實際情況修改)
    time[0] = 0x00; // 秒
    time[1] = 0x56; // 分
    time[2] = 0x17; // 時
    time[3] = 0x26; // 日
    time[4] = 0x09; // 月
    time[5] = 0x03; // 星期
    time[6] = 0x23; // 年
    ds1302_write_time();

    current_altitude = 0;
    current_azimuth = 0;

    while (1) {
        ds1302_read_time(); // 讀取時間

        btn_value = button_scan(); // 掃描按鈕

        if (btn_value == 1) { // 模式切換
            mode = !mode;
        }

        if (mode == 0) { // 自動模式
            lcd_display_string(0, 0, "Auto Mode       ");
            // update_motor_position(); // 先注釋掉原來的調用

            auto_update_counter++;
            if (auto_update_counter >= 300) { // 30 秒
                update_motor_position();
                auto_update_counter = 0; // 清零
            }
        }
         else { // 手動模式
            lcd_display_string(0, 0, "Manual Mode     ");
            if (btn_value == 2) { // 上
                motor_rotate(0, 1); // 每次只走一步
                current_altitude += MOTOR_STEP_ANGLE; //每次只增加一步
                if (current_altitude < 0) current_altitude = 0; // 限制下限
            }
            if (btn_value == 3) { // 下
                motor_rotate(0, -1); //每次只走一步
                current_altitude -= MOTOR_STEP_ANGLE; //每次只減少一步
                if (current_altitude > MAX_ALTITUDE_STEPS * MOTOR_STEP_ANGLE) current_altitude = MAX_ALTITUDE_STEPS * MOTOR_STEP_ANGLE; //限制上限
            }
            if (btn_value == 4) { // 左
                motor_rotate(1, -1); //每次只走一步
                current_azimuth -= MOTOR_STEP_ANGLE; //每次只減少一步
                current_azimuth = fmod(current_azimuth, 360.0); // 限制在 0-360 度
                if (current_azimuth < 0) current_azimuth += 360.0; // 負數轉正數

            }
            if (btn_value == 5) { // 右
                motor_rotate(1, 1); //每次只走一步
                current_azimuth += MOTOR_STEP_ANGLE;  //每次只增加一步
                current_azimuth = fmod(current_azimuth, 360.0); // 限制在 0-360 度
            }
        }

        // 限幅處理, 用于顯示
        displayed_altitude = current_altitude;
        displayed_azimuth = current_azimuth;

        if (displayed_altitude < 0) displayed_altitude = 0;
        if (displayed_altitude > MAX_ALTITUDE_STEPS * MOTOR_STEP_ANGLE) displayed_altitude = MAX_ALTITUDE_STEPS * MOTOR_STEP_ANGLE;

        // 顯示當前角度 (使用限幅后的值)
        sprintf(display_str, "A:%.1f E:%.1f", displayed_azimuth, displayed_altitude);
        lcd_display_string(0, 1, display_str);

        delay(100); // 延時
    }


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

12#
ID:1145974 發表于 2025-4-9 20:32 | 只看該作者
找朋友幫忙看了,發現是程序的問題,現在的ai還是比較弱的,寫程序還是一般,只能保證能編譯但是不能完全實現功能。現在已經搞定問題了,需要的功能都能實現了,謝謝大家的幫助了。
回復

使用道具 舉報

11#
ID:536683 發表于 2025-3-31 11:59 | 只看該作者
查一下硬件,線序接錯了,也會只震動,不轉。
回復

使用道具 舉報

10#
ID:69038 發表于 2025-3-30 10:17 | 只看該作者
會震動不會轉,要么時序出錯,要么丟步。
回復

使用道具 舉報

9#
ID:102168 發表于 2025-3-29 23:16 | 只看該作者
HAOHAO567 發表于 2025-3-29 16:02
但是他驅動板上的ABCD的相序燈是能輪著亮的,我也試過5v電池單獨接一個電機,他也是不轉,只會震動,我現在 ...

你用的這個步進電機帶減速齒輪,速度轉起來估計也不會太快,
你能看到相序燈切換,說明你給的脈沖頻率很低了,再加上減速齒輪的作用,最后輸出軸轉得就更慢了。
你可以在輸出軸上粘貼個長點的紙片什么的,這樣有轉動了也看得明顯一些,多轉一會兒看看變化。
回復

使用道具 舉報

8#
ID:1145974 發表于 2025-3-29 16:02 | 只看該作者
但是他驅動板上的ABCD的相序燈是能輪著亮的,我也試過5v電池單獨接一個電機,他也是不轉,只會震動,我現在買了另外一家店的電機,看看是不是電機的問題。

51hei圖片_20250329160012.jpg (357.65 KB, 下載次數: 0)

51hei圖片_20250329160012.jpg
回復

使用道具 舉報

7#
ID:1145974 發表于 2025-3-29 15:59 | 只看該作者
chxelc 發表于 2025-3-29 14:09
把延時時間改長或者改短看看。delay(50)那里。

我程序的延時(50改成2和5)和電機的延時(100改成50)我都改了,也不行.我打算換一家店的電機了。
回復

使用道具 舉報

6#
ID:517466 發表于 2025-3-29 15:07 | 只看該作者
建議你按照如下步驟調整程序
1、處理注釋掉主程序中初始化以外的所有處理
2、將步進電機的正反向驅動寫成函數形式
3、在主程序中先測試電機的正反轉,看成不成功
4、第三步成功了以后,再去把時鐘部分和步進電機的部分整合起來。

單獨函數化及測試步進電機的驅動,應該不麻煩。電機的正反轉函數,按照單步方式書寫。多步函數,按照步數調用單步函數。整個程序盡可能都函數化編程,這樣邏輯關系清晰。
回復

使用道具 舉報

5#
ID:712097 發表于 2025-3-29 14:09 | 只看該作者
把延時時間改長或者改短看看。delay(50)那里。
回復

使用道具 舉報

地板
ID:469589 發表于 2025-3-29 13:13 | 只看該作者
一般啟動速度太低或太高都會有這種現象,供參考
回復

使用道具 舉報

板凳
ID:469589 發表于 2025-3-29 12:40 | 只看該作者
啟動速度太快了,慢慢的啟動
回復

使用道具 舉報

沙發
ID:1145974 發表于 2025-3-29 08:01 | 只看該作者
一直不成功,就只有電機不轉的問題了,我真的搞不明白,各位大哥幫幫我
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 999精品在线观看 | 日韩国产精品一区二区三区 | 999免费网站| 亚洲三级av | 久久精品久久精品久久精品 | 日韩电影中文字幕 | 欧美黑人一级爽快片淫片高清 | 手机在线不卡av | 欧美成人精品一区二区男人看 | 国产精品一区二区三区在线 | 91精品国产乱码久久蜜臀 | 日韩亚洲一区二区 | xx性欧美肥妇精品久久久久久 | 成人av一区二区三区 | 亚洲精品天堂 | 日韩欧美精品在线 | 亚洲视频在线一区 | 一区二区三区日韩精品 | 夜久久| 日韩激情视频一区 | 国产乱码精品1区2区3区 | 久久久久久久久久久一区二区 | 黑人精品 | 久久久91精品国产一区二区三区 | 亚洲一区国产 | 久久精品国产一区二区电影 | 久久久久久久久99精品 | 777zyz色资源站在线观看 | 亚洲精品乱码久久久久v最新版 | 欧美日韩国产在线观看 | 91久久久久久久久久久久久 | 蜜桃视频在线观看免费视频网站www | 国产美女视频一区 | 精精精精xxxx免费视频 | h片在线观看网站 | 国产精品一区二区在线免费观看 | 亚洲精品一区二区三区在线 | 亚洲免费视频一区二区 | 欧美性video 精品亚洲一区二区 | 久久久精品一区二区三区四季av | av在线电影网站 |