【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的时序图,然后对着时序图 读状态 写指令 读数据 写数据。 这东西对曾经只想完成老师作业的我来说简直就是一种折磨。

相关文章
|
10天前
|
人工智能 数据管理 API
阿里云百炼又获大奖!阿里云百炼入选 2024 最受开发者欢迎的 AI 应用开发平台榜15强
2024年最受开发者欢迎的AI应用开发平台榜单发布,阿里云百炼入选15强。持续推动AI开发者生态建设,提供开放平台、培训支持、行业解决方案,注重数据安全与合规,致力于生态合作与共赢,加速企业数智化转型。
|
10天前
|
人工智能 安全 测试技术
EXAONE 3.5:LG 推出的开源 AI 模型,采用 RAG 和多步推理能力降低模型的幻觉问题
EXAONE 3.5 是 LG AI 研究院推出的开源 AI 模型,擅长长文本处理,能够有效降低模型幻觉问题。该模型提供 24 亿、78 亿和 320 亿参数的三个版本,支持多步推理和检索增强生成技术,适用于多种应用场景。
57 9
EXAONE 3.5:LG 推出的开源 AI 模型,采用 RAG 和多步推理能力降低模型的幻觉问题
|
12天前
|
机器学习/深度学习 人工智能
SNOOPI:创新 AI 文本到图像生成框架,提升单步扩散模型的效率和性能
SNOOPI是一个创新的AI文本到图像生成框架,通过增强单步扩散模型的指导,显著提升模型性能和控制力。该框架包括PG-SB和NASA两种技术,分别用于增强训练稳定性和整合负面提示。SNOOPI在多个评估指标上超越基线模型,尤其在HPSv2得分达到31.08,成为单步扩散模型的新标杆。
53 10
SNOOPI:创新 AI 文本到图像生成框架,提升单步扩散模型的效率和性能
|
12天前
|
人工智能 搜索推荐 开发者
Aurora:xAI 为 Grok AI 推出新的图像生成模型,xAI Premium 用户可无限制访问
Aurora是xAI为Grok AI助手推出的新图像生成模型,专注于生成高逼真度的图像,特别是在人物和风景图像方面。该模型支持文本到图像的生成,并能处理包括公共人物和版权形象在内的多种图像生成请求。Aurora的可用性因用户等级而异,免费用户每天能生成三张图像,而Premium用户则可享受无限制访问。
53 11
Aurora:xAI 为 Grok AI 推出新的图像生成模型,xAI Premium 用户可无限制访问
|
16天前
|
人工智能 编解码 网络架构
GenCast:谷歌DeepMind推出的AI气象预测模型
GenCast是由谷歌DeepMind推出的革命性AI气象预测模型,基于扩散模型技术,提供长达15天的全球天气预报。该模型在97.2%的预测任务中超越了全球顶尖的中期天气预报系统ENS,尤其在极端天气事件的预测上表现突出。GenCast能在8分钟内生成预报,显著提高预测效率,并且已经开源,包括代码和模型权重,支持更广泛的天气预报社区和研究。
109 14
GenCast:谷歌DeepMind推出的AI气象预测模型
|
13天前
|
存储 人工智能 PyTorch
【AI系统】模型转换流程
本文详细介绍了AI模型在不同框架间的转换方法,包括直接转换和规范式转换两种方式。直接转换涉及从源框架直接生成目标框架的模型文件,而规范式转换则通过一个中间标准格式(如ONNX)作为桥梁,实现模型的跨框架迁移。文中还提供了具体的转换流程和技术细节,以及模型转换工具的概览,帮助用户解决训练环境与部署环境不匹配的问题。
32 5
【AI系统】模型转换流程
|
17天前
|
机器学习/深度学习 存储 人工智能
EfficientTAM:Meta AI推出的视频对象分割和跟踪模型
EfficientTAM是Meta AI推出的轻量级视频对象分割和跟踪模型,旨在解决SAM 2模型在移动设备上部署时的高计算复杂度问题。该模型采用非层次化Vision Transformer(ViT)作为图像编码器,并引入高效记忆模块,以降低计算复杂度,同时保持高质量的分割结果。EfficientTAM在多个视频分割基准测试中表现出与SAM 2相当的性能,具有更快的处理速度和更少的参数,特别适用于移动设备上的视频对象分割应用。
36 9
EfficientTAM:Meta AI推出的视频对象分割和跟踪模型
|
13天前
|
机器学习/深度学习 存储 人工智能
【AI系统】模型转换基本介绍
模型转换技术旨在解决深度学习模型在不同框架间的兼容性问题,通过格式转换和图优化,将训练框架生成的模型适配到推理框架中,实现高效部署。这一过程涉及模型格式转换、计算图优化、算子统一及输入输出支持等多个环节,确保模型能在特定硬件上快速、准确地运行。推理引擎作为核心组件,通过优化阶段和运行阶段,实现模型的加载、优化和高效执行。面对不同框架的模型文件格式和网络结构,推理引擎需具备高度的灵活性和兼容性,以支持多样化的应用场景。
35 4
【AI系统】模型转换基本介绍
|
13天前
|
机器学习/深度学习 人工智能 算法
【AI系统】模型压缩基本介绍
模型压缩旨在通过减少存储空间、降低计算量和提高计算效率,降低模型部署成本,同时保持模型性能。主要技术包括模型量化、参数剪枝、知识蒸馏和低秩分解,广泛应用于移动设备、物联网、在线服务系统、大模型及自动驾驶等领域。
49 4
【AI系统】模型压缩基本介绍
|
13天前
|
机器学习/深度学习 存储 人工智能
【AI系统】模型剪枝
本文概述了模型剪枝的概念、方法及流程,旨在通过移除神经网络中冗余或不重要的参数,实现模型规模的减小和效率的提升。剪枝不仅有助于降低模型的存储和计算需求,还能增强模型的泛化能力。文章详细介绍了剪枝的定义、分类、不同阶段的剪枝流程,以及多种剪枝算法,如基于参数重要性的方法、结构化剪枝、动态剪枝和基于优化算法的全局剪枝策略。通过这些方法,可以在保持模型性能的同时,显著提高模型的计算速度和部署灵活性。
27 2
【AI系统】模型剪枝
下一篇
DataWorks