【51单片机】单片机开发者的福音: 让AI看电路图帮你编写程序(使用ChatGPT 中训练好的单片机工程师模型)

简介: 使用AI大语言模型编写 单片机程序. 使用的是 OpenAI公司发布的 ChatGPT .在ChatGPT上有别人训练好的 单片机工程师 with Keil uVision 5 - C Code Explainer模型, 可以上传电路图改模型可以通过这个用户所给的电路图进行编程.


这里使用的人工智能是 OpenAI公司开发的 ChatGPT.为了让AI用起来更加的顺手我们可以选择单片机工程师这个训练好的模型,当然用原本的ChatGPT-4o也是挺好用的.

第0步 需要准备东西

1. 科学上网

2. 电路图 (可以是pdf文件\也可是高清的png或者jpg图片)

第1步 寻找一个适合自己的模型

可以点开链接直达这个模型单片机工程师 with keil uvision 5,或者登录后按照下图的方式找到这个模型.

第2步 沟通方式

公式 : 介绍+目的+要求

例子:

因为chatGPT 联系上下文的能力很强, 除了第一次沟通的时候发送文件介绍之外,在此对话的时候就可以不用发送了.就是当做一个仆人一样来对话就好, 它给我们程序,我们拿去编译 下载就好,不满足我们的要求就接着和它沟通,只要你把问题和你想要的效果描述清楚,它基本上都能完成的很好,大大提高你的工作效率.

看看这次AI的回答:

我们可以看到 , 它给出了

#include "lcd1602.h"
#include "ds1302.h"

这两个库我们是没有的,所以呢 我们具体的情况还要给ai说明白,我们没有ds1302这个芯片, 也没有lcd1602.h这个库,需要自己写

进一步说明情况

请看ai的这次回答: 我个人认为应该是没什么问题,它把lcd1602模块给单独拿来出来方便我们复用,下面是ai的回答:

好的,我们可以不使用DS1302芯片,直接在程序中预设时间信息为“23:55”,并使用定时器来模拟时间的递增。以下是修改后的完整代码,包括LCD1602的驱动程序和时间的显示功能。

LCD1602驱动程序 (lcd1602.hlcd1602.c)

lcd1602.h

#ifndef _LCD1602_H_
#define _LCD1602_H_
#include <reg51.h>
sbit RS = P2^0;  // RS引脚
sbit RW = P2^1;  // RW引脚
sbit E  = P2^2;  // E引脚
sbit D4 = P2^4;  // 数据引脚 D4
sbit D5 = P2^5;  // 数据引脚 D5
sbit D6 = P2^6;  // 数据引脚 D6
sbit D7 = P2^7;  // 数据引脚 D7
void LCD_Init(void);
void LCD_Cmd(unsigned char cmd);
void LCD_Data(unsigned char dat);
void LCD_ShowString(unsigned char x, unsigned char y, char *str);
void LCD_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len);
void LCD_ShowChar(unsigned char x, unsigned char y, char ch);
#endif

lcd1602.c

#include "lcd1602.h"
// 延时函数
void Delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 114; j++);
}
// 发送命令到LCD
void LCD_Cmd(unsigned char cmd) {
    RS = 0;
    RW = 0;
    E  = 1;
    D4 = cmd & 0x10;
    D5 = cmd & 0x20;
    D6 = cmd & 0x40;
    D7 = cmd & 0x80;
    E  = 0;
    E  = 1;
    D4 = cmd & 0x01;
    D5 = cmd & 0x02;
    D6 = cmd & 0x04;
    D7 = cmd & 0x08;
    E  = 0;
    Delay(2);
}
// 发送数据到LCD
void LCD_Data(unsigned char dat) {
    RS = 1;
    RW = 0;
    E  = 1;
    D4 = dat & 0x10;
    D5 = dat & 0x20;
    D6 = dat & 0x40;
    D7 = dat & 0x80;
    E  = 0;
    E  = 1;
    D4 = dat & 0x01;
    D5 = dat & 0x02;
    D6 = dat & 0x04;
    D7 = dat & 0x08;
    E  = 0;
    Delay(2);
}
// 初始化LCD1602
void LCD_Init(void) {
    LCD_Cmd(0x02);  // 初始化指令
    LCD_Cmd(0x28);  // 4位数据接口, 2行显示, 5x7点阵
    LCD_Cmd(0x0C);  // 显示开,光标关
    LCD_Cmd(0x06);  // 数据输入后,光标右移
    LCD_Cmd(0x01);  // 清屏
}
// 显示字符串
void LCD_ShowString(unsigned char x, unsigned char y, char *str) {
    unsigned char addr;
    if (y == 0)
        addr = 0x80 + x;
    else
        addr = 0xC0 + x;
    LCD_Cmd(addr);
    while (*str)
        LCD_Data(*str++);
}
// 显示数字
void LCD_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len) {
    unsigned char t, temp;
    unsigned char show_flag = 0;
    for (t = 0; t < len; t++) {
        temp = (num / 10000) % 10;
        if (show_flag == 0 && t < len - 1) {
            if (temp == 0)
                LCD_Data(' ');
            else {
                show_flag = 1;
                LCD_Data(temp + '0');
            }
        } else
            LCD_Data(temp + '0');
        num *= 10;
    }
}
// 显示单个字符
void LCD_ShowChar(unsigned char x, unsigned char y, char ch) {
    unsigned char addr;
    if (y == 0)
        addr = 0x80 + x;
    else
        addr = 0xC0 + x;
    LCD_Cmd(addr);
    LCD_Data(ch);
}

主程序 (main.c)

#include <reg51.h>
#include "lcd1602.h"
// 定义全局变量来存储时间
unsigned char hour = 23, minute = 55, second = 0;
// 定时器中断函数,每1秒调用一次
void Timer0_ISR(void) interrupt 1 {
    TH0 = 0xFC;  // 重装载定时器初值
    TL0 = 0x18;
    
    second++;
    if (second == 60) {
        second = 0;
        minute++;
        if (minute == 60) {
            minute = 0;
            hour++;
            if (hour == 24)
                hour = 0;
        }
    }
}
// 定时器0初始化
void Timer0_Init() {
    TMOD = 0x01;  // 设置定时器0为模式1(16位定时器)
    TH0 = 0xFC;   // 设置定时器初值,使得1秒触发一次中断
    TL0 = 0x18;
    ET0 = 1;      // 使能定时器0中断
    EA  = 1;      // 使能总中断
    TR0 = 1;      // 启动定时器0
}
void main() {
    LCD_Init();      // 初始化LCD1602
    Timer0_Init();   // 初始化定时器
    while(1) {
        // 在LCD1602上显示时间
        LCD_ShowString(0, 0, "Time:");
        LCD_ShowNum(5, 0, hour, 2);   // 显示小时
        LCD_ShowChar(7, 0, ':');
        LCD_ShowNum(8, 0, minute, 2); // 显示分钟
        LCD_ShowChar(10, 0, ':');
        LCD_ShowNum(11, 0, second, 2); // 显示秒
        
        Delay(1000);  // 刷新间隔
    }
}

说明:

  1. LCD1602驱动lcd1602.hlcd1602.c文件实现了LCD1602的初始化和显示功能,包括显示字符串、数字和单个字符。
  2. 定时器模拟时钟:定时器0的中断每秒触发一次,用于更新秒、分钟和小时变量,并将其显示在LCD1602上。
  3. 程序结构:主程序通过循环不断更新LCD1602上的时间显示。

编译和运行:

  1. 将上述代码分别保存到lcd1602.hlcd1602.cmain.c中。
  2. 使用Keil uVision 5进行编译并将程序下载到开发板上。
  3. 观察LCD1602上显示的时间变化。

这个程序将在开始时显示"23:55",然后每秒自动递增,模拟时钟功能。

总之它给程序,你就拿到你的板子上进行调试即可,还不满意你就让它改.

但是由于你不是plus用户, 用多了可能就回出现(提醒你该充钱或者切换账号)

没钱有没钱的办法,可以使用 copilot 请看这篇文章【51单片机】让AI识别电路图,帮你进行编码(以51单片机为例)


这是我让AI实现的万年历功能,阅读代码其实我们不难看出ai的创造性思维是不如人类的, 就比如它不知道如何把独立按键发挥到极致,让时间日期数值可以增加可以减小,程序中它只有增加没有减小的逻辑,对用户来说体验感就大打折扣.我们能做的就是继续和它沟通完善程序,或者自己修改程序.

要实现一个万年历功能,显示时间和日期,并且可以通过独立按键修改时间和日期,需要按照以下步骤进行设计和实现。这个程序将使用8051单片机、LCD1602显示屏、以及独立按键来实现时间和日期的显示和调整。

功能实现概要:

  1. 显示内容:在LCD1602上显示当前的日期和时间。
  2. 时间日期初始化:初始时间为2024年8月15日16:19:15。
  3. 时间更新:使用定时器中断每秒更新一次时间。
  4. 独立按键调整时间日期:使用三个独立按键分别调整小时、分钟和日期。

硬件连接假设:

  • LCD1602:数据线接P2口,控制线RS、RW、E分别接P2.0、P2.1、P2.2。
  • 按键:三个独立按键分别接P3.0(调整小时)、P3.1(调整分钟)、P3.2(调整日期)。

万年历功能代码

lcd1602.h

#ifndef _LCD1602_H_
#define _LCD1602_H_
#include <reg51.h>
sbit RS = P2^0;  // RS引脚
sbit RW = P2^1;  // RW引脚
sbit E  = P2^2;  // E引脚
sbit D4 = P2^4;  // 数据引脚 D4
sbit D5 = P2^5;  // 数据引脚 D5
sbit D6 = P2^6;  // 数据引脚 D6
sbit D7 = P2^7;  // 数据引脚 D7
void LCD_Init(void);
void LCD_Cmd(unsigned char cmd);
void LCD_Data(unsigned char dat);
void LCD_ShowString(unsigned char x, unsigned char y, char *str);
void LCD_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len);
void LCD_ShowChar(unsigned char x, unsigned char y, char ch);
#endif

lcd1602.c

#include "lcd1602.h"
// 延时函数
void Delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 114; j++);
}
// 发送命令到LCD
void LCD_Cmd(unsigned char cmd) {
    RS = 0;
    RW = 0;
    E  = 1;
    D4 = cmd & 0x10;
    D5 = cmd & 0x20;
    D6 = cmd & 0x40;
    D7 = cmd & 0x80;
    E  = 0;
    E  = 1;
    D4 = cmd & 0x01;
    D5 = cmd & 0x02;
    D6 = cmd & 0x04;
    D7 = cmd & 0x08;
    E  = 0;
    Delay(2);
}
// 发送数据到LCD
void LCD_Data(unsigned char dat) {
    RS = 1;
    RW = 0;
    E  = 1;
    D4 = dat & 0x10;
    D5 = dat & 0x20;
    D6 = dat & 0x40;
    D7 = dat & 0x80;
    E  = 0;
    E  = 1;
    D4 = dat & 0x01;
    D5 = dat & 0x02;
    D6 = dat & 0x04;
    D7 = dat & 0x08;
    E  = 0;
    Delay(2);
}
// 初始化LCD1602
void LCD_Init(void) {
    LCD_Cmd(0x02);  // 初始化指令
    LCD_Cmd(0x28);  // 4位数据接口, 2行显示, 5x7点阵
    LCD_Cmd(0x0C);  // 显示开,光标关
    LCD_Cmd(0x06);  // 数据输入后,光标右移
    LCD_Cmd(0x01);  // 清屏
}
// 显示字符串
void LCD_ShowString(unsigned char x, unsigned char y, char *str) {
    unsigned char addr;
    if (y == 0)
        addr = 0x80 + x;
    else
        addr = 0xC0 + x;
    LCD_Cmd(addr);
    while (*str)
        LCD_Data(*str++);
}
// 显示数字
void LCD_ShowNum(unsigned char x, unsigned char y, unsigned int num, unsigned char len) {
    unsigned char t, temp;
    unsigned char show_flag = 0;
    for (t = 0; t < len; t++) {
        temp = (num / 10000) % 10;
        if (show_flag == 0 && t < len - 1) {
            if (temp == 0)
                LCD_Data(' ');
            else {
                show_flag = 1;
                LCD_Data(temp + '0');
            }
        } else
            LCD_Data(temp + '0');
        num *= 10;
    }
}
// 显示单个字符
void LCD_ShowChar(unsigned char x, unsigned char y, char ch) {
    unsigned char addr;
    if (y == 0)
        addr = 0x80 + x;
    else
        addr = 0xC0 + x;
    LCD_Cmd(addr);
    LCD_Data(ch);
}

主程序 (main.c)

#include <reg51.h>
#include "lcd1602.h"
// 定义引脚
sbit Key1 = P3^0;  // 调整小时
sbit Key2 = P3^1;  // 调整分钟
sbit Key3 = P3^2;  // 调整日期
// 时间和日期变量
unsigned int year = 2024;
unsigned char month = 8, day = 15, hour = 16, minute = 19, second = 15;
// 检测按键按下状态的函数
bit Key_Pressed(sbit key) {
    if (!key) {      // 如果按键被按下
        Delay(20);   // 消抖延时
        if (!key) {  // 确认按下
            while (!key);  // 等待按键释放
            return 1;
        }
    }
    return 0;
}
// 更新时间函数
void Update_Time() {
    second++;
    if (second == 60) {
        second = 0;
        minute++;
        if (minute == 60) {
            minute = 0;
            hour++;
            if (hour == 24) {
                hour = 0;
                day++;
                // 判断每月天数
                if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day == 32) {
                    day = 1;
                    month++;
                } else if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
                    day = 1;
                    month++;
                } else if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)) { // 闰年
                    if (day == 30) {
                        day = 1;
                        month++;
                    }
                } else if (month == 2 && day == 29) {
                    day = 1;
                    month++;
                }
                if (month == 13) {
                    month = 1;
                    year++;
                }
            }
        }
    }
}
// 定时器中断函数,每1秒调用一次
void Timer0_ISR(void) interrupt 1 {
    TH0 = 0xFC;  // 重装载定时器初值
    TL0 = 0x18;
    
    Update_Time();
}
// 定时器0初始化
void Timer0_Init() {
    TMOD = 0x01;  // 设置定时器0为模式1(16位定时器)
    TH0 = 0xFC;   // 设置定时器初值,使得1秒触发一次中断
    TL0 = 0x18;
    ET0 = 1;      // 使能定时器0中断
    EA  = 1;      // 使能总中断
    TR0 = 1;      // 启动定时器0
}
void main() {
    LCD_Init();      // 初始化LCD1602
    Timer0_Init();   // 初始化定时器
    while(1) {
        // 检测按键,调整时间和日期
        if (Key_Pressed(Key1)) {
            hour++;
            if (hour == 24) hour = 0;
        }
        if (Key_Pressed(Key2)) {
            minute++;
            if (minute == 60) minute = 0;
        }
        if (Key_Pressed(Key3)) {
            day++;
            // 需要根据月份判断天数
            if ((month == 1 || month == 
3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day == 32) {
                day = 1;
                month++;
            } else if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
                day = 1;
                month++;
            } else if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)) { // 闰年
                if (day == 30) {
                    day = 1;
                    month++;
                }
            } else if (month == 2 && day == 29) {
                day = 1;
                month++;
            }
            if (month == 13) {
                month = 1;
                year++;
            }
        }
        // 在LCD1602上显示日期
        LCD_ShowString(0, 0, "Date:");
        LCD_ShowNum(5, 0, year, 4);  // 显示年份
        LCD_ShowChar(9, 0, '-');
        LCD_ShowNum(10, 0, month, 2); // 显示月份
        LCD_ShowChar(12, 0, '-');
        LCD_ShowNum(13, 0, day, 2);  // 显示日期
        
        // 在LCD1602上显示时间
        LCD_ShowString(0, 1, "Time:");
        LCD_ShowNum(5, 1, hour, 2);  // 显示小时
        LCD_ShowChar(7, 1, ':');
        LCD_ShowNum(8, 1, minute, 2); // 显示分钟
        LCD_ShowChar(10, 1, ':');
        LCD_ShowNum(11, 1, second, 2); // 显示秒
        
        Delay(100);  // 刷新间隔
    }
}

说明:

  1. LCD1602驱动lcd1602.hlcd1602.c文件实现了LCD1602的初始化和显示功能,包括显示字符串、数字和单个字符。
  2. 时间和日期更新:定时器0中断每秒触发一次,更新秒、分钟、小时、天、月和年。
  3. 按键调整:三个独立按键分别用于调整小时、分钟和日期。
  4. 闰年判断:程序中对2月份日期进行了闰年的判断和处理。
  5. 程序结构:主程序通过循环不断检测按键输入,并在LCD1602上实时更新日期和时间显示。

编译和运行:

  1. 将上述代码分别保存到lcd1602.hlcd1602.cmain.c中。
  2. 使用Keil uVision 5进行编译,并将程序下载到开发板上。
  3. 通过按键调整时间和日期,并观察LCD1602上显示的结果。

这个程序实现了一个简单的万年历功能,可以显示时间和日期,并且通过按键进行调整。你可以根据需求进一步修改或扩展功能。

当然,AI对程序某个部分的驱动其实是值得我们学习的, 比如按键消抖和lcd1602的驱动等等。如果你是初学的你可能很难理解按键消抖,也很难理解LCD1602的时序图,然后对着时序图 读状态 写指令 读数据 写数据。 这东西对曾经只想完成老师作业的我来说简直就是一种折磨。

相关文章
|
1月前
|
云安全 人工智能 自然语言处理
阿里云x硅基流动:AI安全护栏助力构建可信模型生态
阿里云AI安全护栏:大模型的“智能过滤系统”。
|
1月前
|
人工智能 搜索推荐 程序员
当AI学会“跨界思考”:多模态模型如何重塑人工智能
当AI学会“跨界思考”:多模态模型如何重塑人工智能
246 120
|
29天前
|
机器学习/深度学习 人工智能 自然语言处理
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
228 37
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
|
25天前
|
人工智能 开发者
从技术到品牌:一个AI指令,让开发者也能写出动人的品牌故事
开发者常擅技术却困于品牌叙事。本文分享一套结构化AI指令,结合DeepSeek、通义千问等国产工具,将品牌故事拆解为可执行模块,助力技术人快速生成有温度、有逻辑的品牌故事框架,实现从代码到共鸣的跨越。
128 5
|
28天前
|
数据采集 人工智能 程序员
PHP 程序员如何为 AI 浏览器(如 ChatGPT Atlas)优化网站
OpenAI推出ChatGPT Atlas,标志AI浏览器新方向。虽未颠覆现有格局,但为开发者带来新机遇。PHP建站者需关注AI爬虫抓取特性,优化技术结构(如SSR、Schema标记)、提升内容可读性与语义清晰度,并考虑未来agent调用能力。通过robots.txt授权、结构化数据、内容集群与性能优化,提升网站在AI搜索中的可见性与引用机会,提前布局AI驱动的流量新格局。
96 8
|
1月前
|
人工智能 Cloud Native 算法
拔俗云原生 AI 临床大数据平台:赋能医学科研的开发者实践
AI临床大数据科研平台依托阿里云、腾讯云,打通医疗数据孤岛,提供从数据治理到模型落地的全链路支持。通过联邦学习、弹性算力与安全合规技术,实现跨机构协作与高效训练,助力开发者提升科研效率,推动医学AI创新落地。(238字)
|
1月前
|
数据采集 人工智能 算法
拔俗AI信息化系统开发:开发者必须啃下的三块技术硬骨头
企业数字化转型中,AI系统成刚需。开发者需攻克三大难关:精准拆解模糊需求,确保业务与技术对齐;严控数据质量,构建持续迭代的数据闭环;实现模型在产线的高效、稳定落地。技术与场景深度融合,方能跨越从“能用”到“好用”的鸿沟。(238字)
|
28天前
|
人工智能 运维 Kubernetes
Serverless 应用引擎 SAE:为传统应用托底,为 AI 创新加速
在容器技术持续演进与 AI 全面爆发的当下,企业既要稳健托管传统业务,又要高效落地 AI 创新,如何在复杂的基础设施与频繁的版本变化中保持敏捷、稳定与低成本,成了所有技术团队的共同挑战。阿里云 Serverless 应用引擎(SAE)正是为应对这一时代挑战而生的破局者,SAE 以“免运维、强稳定、极致降本”为核心,通过一站式的应用级托管能力,同时支撑传统应用与 AI 应用,让企业把更多精力投入到业务创新。
376 29