找回密码
 立即注册
查看: 2161|回复: 23

当传统89C52单片机开发学习板遇到AI8051U(DIP40)时

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-5 10:36:37 | 显示全部楼层 |阅读模式

当传统STC89C52单片机开发学习板遇到AI8051U(DIP40)时

QX-MCS51_V3.0开发板A.jpg

这是本人在"初试8051U,做个小实验..."一帖中用到的QX-MCS51_V3.0单片机开发学习板。https://www.stcaimcu.com/forum.php?mod=viewthread&tid=9591&extra=page%3D1

平心而论,STC89C52还是一块很不错的芯片,印象中,好像就是它这个系列,开创了51单片机串口下载仿真调试的先河。因此,多年以来,市面上所看到的大多数51单片机开发板,几乎都是基于这块芯片而设计的。 QX-MCS51开发板与其他品牌的51单片机开发板一样,都具备STC89C52本身功能的基本实验条件。 而如今AI8051U的问世,特别是DIP40封装AI8051U的出现,使得STC89C52大有被完全取代的可能。

然而,取代也并非是闭着眼睛、可随意为之的。 尤其是新手初学者,本人在学习实验中,有几点思考和体会,在此聊聊... 当AI8051U(DIP40)插入原来STC89C52位置时:

1,引脚对比分析

STC8051U_DIP40引脚定义.jpg

上图对比,显然AI8051U的功能多了许多。除了电源、接地和P0-P3(8*4=32)以外,不同之处有: 第9脚: 复位RST端。 原STC89C52的复位端是高电平复位,而AI8051U的复位端是低电平复位。 因此,开发板上的复位按钮对AI8051U不起复位作用。 在实验时,可通过P47RST=0将此脚作为普通IO用。 第18,19脚:原接外部晶振(12MHz)。 AI8051U无需外接晶振。因此可将原晶振拔出,使得此两脚悬空。 在实验时,可作为P56、P57使用,多了两个IO。 第29、30脚:原用于外部存储器锁存使能控制,一般STC89C52开发板,不访问外部存储器,都会将此脚悬空,直接引到外部排针。

因此,当插入AI8051U实验时,就可利用此两脚,做有关P44、P45的实验。 第31脚:EA,原外部地址总线使能脚,一般STC89C52开发板,不访问外部存储器,都会将此脚上拉至VCC。 因此,当插入AI8051U做实验时,就牺牲了此引脚,不要做有关P46的实验。

2,下载调试接口 原STC89C52开发板是利用P30、P31串口作为下载和仿真调试口的。 众多STC89C52开发板也增添了电路,考虑了自动断电上电功能,QX-MCS51开发板也不例外,并在这方面做得比较好。 在做STC89C52实验下载程序时,自动断电上电一直比较顺畅。 因为AI8051U支持串口下载仿真调试,所以不需要做任何改动,可直接用串口下载调试,没有问题。 (AI8051U还支持USB下载调试,笔者已经实验发现,有些开发板,只要做细小改动,也可以实现一根USB线,直接下载调试,将另文描述)

3,主频时钟选择 原STC89C52时利用外部晶振(一般是11.0592MHz或12.00MHz),相对决定了主频。 而AI8051U使用内部晶振,主频可选范围较宽,使用上更为灵活多变,明显展示了AI8051U的优势。

4,编程及初始化IO STC89C52上电时,各IO口默认为准双向模式。 而AI8051U不同,上电时除了P30、P31串口特殊用途之外,其它IO都默认为高阻输入, 因此,在做AI8051U实验时,必须首先对IO模式进行正确初始化。

5,指令模式 AI8051U的CPU支持8bit和32bit指令模式。 当选用8bit指令模式时, 要引用 8bit指令模式的AI8051U.H头文件,使用C51编译器。 当选用32bit指令模式时,要引用32bit指令模式的AI8051U.H头文件,使用C251编译器。 不必试图去做: 将8bit指令模式的程序代码选用C251编译、运行。 或者试图去做: 将32bit指令模式的程序代码选用C51编译、运行。 因为,这毫无意义。

6,软件延时调整 STC89C52可选6T或12T指令周期模式。通常是12T模式。 AI8051U 可选1T或12T指令周期模式。通常是 1T模式。 因此,在相同主频的情况下,通常AI8051U的指令周期要快12倍, 更何况,AI8051U的主频可大幅度提高,所以要充分注意: 原STC89C52的程序代码,未必能完全正常运行。 特别是对于显示屏的驱动,以及像对于DS18B20这样的对时序要求比较严格的器件的读写控制, 在用软件延时的地方,要注意适当的调整,延长延时。

7,注意一下ISP的版本 并非最新的ISP版本,对传统的开发板支持得最舒服的。要保存好各种版本的ISP软件,选用最适合的。 本人体会,对于QX-MCS51开发学习板,STCAI-ISP(V6.94H)较好。

以上,是点滴体会,供共同单片机爱好的坛友参考。

3 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-5 10:39:05 | 显示全部楼层

按照惯例,先来一个跑马灯的实验。

(补充一下此开发板的电原理图,便于读者对照程序容易理解)
QX-MCS51_V3.0开发板电原理图V3.pdf (161.66 KB, 下载次数: 68)
//=========================================================================
// 文件: Main.C
// 硬件: AI8051U @ QX-MCS51 V3.0 学习板
// 功能: AI8051U_32位编程入门初步 + 跑马灯程序
// 端口: 8LED: P1.0--P1.7 输出低电平驱动点亮
// 备注: 下载时选择时钟 24MHZ
// 编程: 浦晓明(浦江一水) 2024-12-04  
//=========================================================================
#include "AI8051U.h"   //包含此头文件后,不需要再包含"reg52.h"头文件
#include <intrins.h>   //包含循环右移函数_crol头文件

#define MAIN_Fosc  24000000L  //定义主时钟(下载时可设定)

//全局变量(便于调试观察)
unsigned char LED=0xFC;
//========================================================================
// 函数: void delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数
// 返回: none.
//========================================================================
void delay_ms(unsigned int  ms)
{ unsigned int i;
  do{ i = MAIN_Fosc / 10000;
      while(--i);
    } while(--ms);
}
//==== 主函数 ============================================================
void main(void)
{ unsigned char i;
  WTST  = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  EAXFR = 1; //扩展寄存器(XFR)访问使能
  CKCON = 0; //提高访问XRAM速度
  //IO端口初始化:准双向口
  P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  P1 = LED;                     //初始化亮灯1111100 点亮两个灯
  //--主循环-----------------
  while(1)
  { for(i = 0; i < 8; i++)  
    { LED = _crol_(LED,1);      //循环左移,LED从右向左移动点亮
      P1 = LED;
      delay_ms(100);        
    }
  }
}
//==== END ==========================================================

01_跑马灯LED.rar (19.62 KB, 下载次数: 54)


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-5 20:53:02 | 显示全部楼层
感谢“国学芯用”和“”两位版主的鲜花鼓励和捧场,以及楼上朋友的点赞。

第二个实验程序是关于数码管显示的
作为一个单片机爱好者, 想必控制数码管显示,应该是一项必须掌握的基本技能了。
这块开发板提供的是8位共阴极的数码管,使用了两片74HC573带锁存功能的8位驱动。
因此,本实验程序是基于这个芯片特点而编写的。
实验的内容看似比较简单。
一上来显示“AI8051U_”;
随后显示PI值“P=3.14159”;        (可以思考一下:如何显示这样一串数据?逐个移位取整求余?)
再显示一个直径变量D“d= 1.00 ”;
然后显示计算的面积值"F=0.78540";
最后进入一个模拟RTC的时钟循环显示。
体现了数码管显示字符串和数值特别是浮点数的编程处理。

主程序:

//********************************************************************************
// 名称: 实验8位数码管动态扫描显示
// 基于: QX-MCS51 V3.0 单片机开发学习板
// 实验: AI8051U 取代 STC89C52 实现8位LED数码管字符串显示.
// 编程: 浦晓明(浦江一水) 2024-12-05
//********************************************************************************
#include "AI8051U.H"
#include "AI8051U_SYS.H"
#include "LED8D.H"

sbit we = P2^7;        //位定义数码管位选锁存器接口
sbit du = P2^6;        //位定义数码管段选锁存器接口
// 常数宏定义
#define   PI    3.14159
/************* 全局变量声明 **************/
char S[16];              //显示字符串缓存
unsigned char hour; //时
unsigned char min;  //分
unsigned char sec;  //秒
float    d,F;            //直径和面积变量  

/*************  外部函数声明和外部变量声明 *****************/
//========================================================================

// 函数: void  delay_ms(unsigned int ms)
// 描述: 毫秒级延时函数。
// 参数: ms,要延时的ms数,自动适应主时钟.
//=====================================================================
void  delay_ms(unsigned int ms)
{ unsigned int i;
  do{ i = MAIN_Fosc / 10000;
      while(--i);
    } while(--ms);
}
/********************** 模拟RTC演示函数 ***********************/
void RTC(void)
{
  if(++sec >= 60)
  { sec = 0;
    if(++min >= 60)
    { min = 0;
      if(++hour >= 24) hour = 0;
    }
  }
  sprintf(S,"%02d-%02d-%02d",hour,min,sec);  //组织字符串
  LED8D_Str(0,S);                //送显示段码缓存  //(指定从0位置开始显示...)   
}
/******************** 主函数 **************************/
void main(void)
{
  SYS_Init();       //系统初始化
  LED8D_Init();   //8数码管和定时器0初始化

  d=1.0;             //直径m  
  F=PI*d*d/4;     //求面积
   
  LED8D_Str(0,"AI8051U_");     //字符串常量直接显示
  delay_ms(3000);                  //延时一下
  sprintf(S,"P=%6.5f",PI);       //浮点数转字符串显示PI值3.14159
  LED8D_Str(0,S);                  //送显示段码缓存(指定从0位置开始显示...)   
  delay_ms(3000);                  //延时一下
  sprintf(S,"D= %5.3f ",d);      //浮点数转字符串显示d直径值
  LED8D_Str(0,S);                  //送显示段码缓存   
  delay_ms(3000);                  //延时一下
  sprintf(S,"F=%6.5f",F);        //浮点数转字符串显示F面积值
  LED8D_Str(0,S);                  //送显示段码缓存   
  delay_ms(3000);                  //延时一下
  
  hour = 11;    //时间初始化
  min  = 59;
  sec  = 58;
  RTC();
  //循环...整型数转字符串显示...
  while(1)
  {
    if(SecOK)     //1s时间到
    { SecOK = 0;
      RTC();      //模拟RTC时钟显示
    }   
  }
}
/***** END *****************************************/
工程文件:供初学单片机技术的爱好者参考。
02_8位数码管显示.rar (32.03 KB, 下载次数: 58)




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-8 09:13:52 | 显示全部楼层
第三个实验包括三个内容:
1, LCD1602显示屏的驱动控制;
2, 四个独立按键的4键8值按键处理;
3, 串口1通讯实验.
最后综合上述三项,做成串口屏:
开机显示
串口通讯000.jpg
当按下4个独立键其中之一时,在显示屏显示键值,
同时向上位机发送信息:按下了哪个键,是短按还是长按.
串口通讯实验.jpg
如果上位机发送"P10*AI8051U*"+回车换行,
那么,显示屏就会在第二行的0位置开始显示"*AI8051U*"字符串,如图:
串口通讯001.jpg

主程序:

/******************************************************************
* 工程: Test AI8051U(DIP40) + LCD1602A
* 基于: QX-MCS51_V3.0(STC89C52)单片机开发学习板
* 实验: LCD1602串口显示屏,8位数据控制,USART1_串口通讯.
* 四键: P30/P31/P32/P33,4键8值.
* 说明: 测试AI8051U在传统51实验板上,不做任何硬件改动的实验...
* 编程: 浦晓明(浦江一水) 2024-12-08 ...
*******************************************************************/
#include <stdio.h>
#include <string.h>
#include "AI8051U.h"
#include "KEY4_IO.H"    //4键盘相关函数
#include "LCD1602.H"    //LCD1602A显示屏相关函数

//波特率计算...      
#define FOSC            11059200UL                      //晶振频率
#define BRT           (256 - FOSC / 115200 / 32)    //按照波特率115200计算


sbit LED0  = P1^7;             //运行指示

char RxBuf[24],k;               //串口接收缓存
unsigned short RxCount=0; //接收计数器
char S[20];                        //LCD显示缓存
unsigned char X,Y;             //坐标
unsigned char RxOK=0;      //串口通信接收到标志

//毫秒级非精确延时
void delay(unsigned int ms)
{ unsigned int x,y;
  for(x = ms; x > 0; x--)
  for(y =114; y > 0; y--);
}
//串口初始化:
void UART_init()
{
  SCON= 0x50;
  TMOD= 0x20; //T1工作模式2  8位自动重装
  TH1 = BRT;    //0xFD;
  TL1 = BRT;    //0xFD; //比特率115200
  TR1 = 1;       //启动T1定时器
  AUXR= 0x40;
  SM0 = 0;
  SM1 = 1;    //串口工作方式1 10位异步
  REN = 1;    //串口允许接收
  ES  = 1;     //串口中断打开
  EA  = 1;     //开总中断
}
/*----------------------------
通过串口1发送单字节数据
----------------------------*/
void SendData(unsigned char ch)
{
  SBUF = ch;                 //写数据到UART数据寄存器
  while(TI == 0);
  TI = 0;
}
/*----------------------------
通过串口1发送字符串
----------------------------*/
void SendString(char *s)
{
  while (*s)                   //检测字符串结束标志
  { SendData(*s++); }   //发送当前字符
}
//--------------------------------------------------------------
// 串口1接收中断服务...
//--------------------------------------------------------------
void UART() interrupt 4
{ unsigned char ch=0;
  if(RI)                //检测是否接收完成
  { ch=SBUF;       //接收单字节
    RI = 0;           //清除标志位
    if(ch==0x0A)  //结尾标志
    { RxOK=1;      //接收到指令串置接收到标志
      if((RxCount>0)&&(RxBuf[RxCount-1]==0x0D))
      { RxBuf[RxCount-1]=0;RxBuf[RxCount]=0; }   //清除0x0D,0x0A
    }
    else if(RxCount<19)RxBuf[RxCount++]=ch;
  }
}
//--------------------------------------------------------------
// 主程序入口
//--------------------------------------------------------------
void main(void)
{ unsigned char i,mode;
  unsigned int wait=0;
  //IO端口初始化
  WTST  = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  EAXFR = 1; //扩展寄存器(XFR)访问使能
  CKCON = 0; //提高访问XRAM速度
  //IO端口初始化//全部为准双向口
  P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
  P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
  P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
  P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
  //外设初始化
  UART_init();
  LCD_Init();        //初始化LCD1602
  LCD_CLS();       //测试清屏函数
  LCD_Blink(0);    //测试函数
  LCD_Cursor(0);  //测试函数
  LCD_SetXY(0,0);//测试函数
  delay(5);
  LED0 = 0; delay(1000); //测试IO口控制 LED0亮
  LED0 = 1; delay(1000); //测试IO口控制 LED0灭  
  //显示屏初始界面  
  LCD_STR(0,0,"AI8051U_@115200_");
  LCD_STR(1,0,"LCD1602__4KEY=00");
  //测试通讯口发送字符串
  SendString("AI8051U_UART1_OK\r\n");
  delay(1000);
  //主循环
  while(1)
  { k=0;
    k=RDKEY();  //扫描按键
    if(k!=0)
    { sprintf(S,"KEY=%02X ",(unsigned int)k);   //当有键按下时, 显示键值,(<1秒为短按 >=1秒为长按)
      LCD_STR(1,10,S);                                   //比如短按Key1,显示=10, 长按显示=11
      P1 = ~k;   //显示键值于LED灯
      switch(k)
      { case 0x10:SendString("短按[K1]...\r\n");break;
        case 0x11:SendString("长按[K1]...\r\n");break;
        case 0x20:SendString("短按[K2]...\r\n");break;
        case 0x21:SendString("长按[K2]...\r\n");break;
        case 0x30:SendString("短按[K3]...\r\n");break;
        case 0x31:SendString("长按[K3]...\r\n");break;
        case 0x40:SendString("短按[K4]...\r\n");break;
        case 0x41:SendString("长按[K4]...\r\n");break;
      }        
    }  
    //运行指示灯...
    if(wait==0)  {  LED0 = 0; }                               // LED亮
    if(wait==200){  LED0 = 1; RxOK=0;RxCount=0;RxBuf[0]=0; }  // LED灭
    wait=wait<2250?wait+1:0;  //计数器循环
    //串口屏通讯处理....
    if(RxOK)  //接收到指令串
    { //解析串口接收指令字符串,显示之
      switch(RxBuf[0])
      { case 'P':  //显示指令
                   X=RxBuf[1]-0x30;
                   Y=RxBuf[2]-0x30; if(Y>9)Y=Y-7;
                   for(i=0;i<RxCount-3;i++){ S=RxBuf[3+i]; S[i+1]=0; }
                   LCD_STR(X,Y,S);  //显示接收字符串
                   break;
        case '@':  X=RxBuf[1]-0x30;
                   Y=RxBuf[2]-0x30; if(Y>9)Y=Y-7;
                   LCD_SetXY(X,Y);  //光标定位
                   break;
        case '_':  mode=RxBuf[1]-0x30;if(mode>0)mode=1;
                   LCD_Cursor(mode);//光标显示        
                   break;
        case '*':  mode=RxBuf[1]-0x30;if(mode>0)mode=1;
                   LCD_Blink(mode); //光标闪动
                   break;
        case 'C':  mode=RxBuf[1]-0x30;
                   if(mode==0)LCD_STR(0,0,"                ");//清屏第一行
                   if(mode==1)LCD_STR(1,0,"                ");//清屏第二行
                                                                         if(mode>=2)LCD_CLS();                      //清全屏
                   break;
        default:   RxBuf[RxCount]=0; SendString(RxBuf); SendData(0x0D); SendData(0x0A); break;  //默认返回原串...
      }
      for(i=0;i<24;i++)RxBuf=0;RxOK=0; RxCount=0;
    }                            //清除接收缓存
    delay(10);     
  }
}
//******************************************************************************
// 附件: LCD1602串口屏通信控制指令协议,115200,8,1,N
//----------------------------------------------------------------------
// 共五条指令, 说明如下...
//----------------------------------------------------------------------
// 1, 格式:  PXYsss...\r\n   +0D+0A
//    其中:  P -- 命令字 指定坐标显示字符串;
//           X -- 显示行坐标, X=0或1,表示第一行或第二行
//           Y -- 显示列坐标, Y=0...F(超过9用ABCDEF的16进制表示)
//           sss... 需要显示的字符串 (长度限于16字符)(LCD1602每行最多显示16字符)   
//           \r\n  发送串结尾标志,回车换行符 即+0x0D+0x0A,(以下同)
//    实例:  P00ABCDEFG+0.1234(\r\n) 在显示屏第一行首显示"ABCDEFG+0.1234"
//----------------------------------------------------------------------
// 2, 格式:  Cm\r\n
//    其中:  C -- 命令字 清屏
//           m -- 参数 0:清第一行 1:清第二行 2:清全屏           
//    实例:  C0\r\n 显示屏第一行被清空;
//----------------------------------------------------------------------
// 3, 格式:  @XY\r\n
//    其中:  @ -- 命令字 指定当前光标坐标
//              X,Y -- 参数 X:行 Y:列           
//    实例:  @01\r\n 当前光标在第一行第1列 (光标是否显示取决于以下指令)
//----------------------------------------------------------------------
// 4, 格式:  *m\r\n
//    其中:  * -- 命令字 光标闪烁显示
//             m -- 参数 0:不闪烁 1:闪烁           
//    实例:  *1 在先前指定的坐标位置闪烁光标;
//----------------------------------------------------------------------
// 5, 格式:  _m\r\n
//    其中:  _ -- 命令字 底画线显示
//             m -- 参数 0:不显示底画线 1:显示底画线           
//    实例:  _1 在先前指定的坐标位置显示底画线; (底画线显示后,光标闪烁取消)
//*******************************************************************************


工程文件, 供初学单片机爱好者参考.
03-LCD1602 4KEY USART1.rar (25.18 KB, 下载次数: 72)

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-9 08:56:09 | 显示全部楼层
第四个实验是关于8x8点阵LED模块的滚动显示.
QX-MCS51开发板套件中配置了一块8x8点阵LED模块. 这种模块可以接连,扩大显示面积.
在现实生活中,点阵LED显示屏,滚动显示字符串较为常见.
本实验在一块点阵显示屏上滚动循环显示96个ASCII码字符. 实践了单片机控制点阵LED模块的基本技术.




主程序:
//==============================================================================================
// 文件: Main.C
// 硬件: AI8051U @ QX-MCS51 V3.0 学习板
// 功能: AI8051U_32位编程入门初步
// 端口: LED8x8点阵显示模块: P3.4-DIN/P3.5-CLK/P3.6-LAT
// 备注: 下载时选择时钟 24MHZ
// 编程: 浦晓明(浦江一水) 2024-12-08  
//==============================================================================================
#include "AI8051U.H"
#include "AI8051U_SYS.H"
#include "ASC8.H"

//点阵模块接口定义
sbit LED8x8_LAT = P3^6;//储存寄存器时钟
sbit LED8x8_CLK = P3^5;//移位寄存器时钟输入端
sbit LED8x8_DIN = P3^4;//串行数据输入端
// --列选通控制-- //
unsigned char code TAB[8]  = { 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F, };
//全局变量
unsigned char ZF[19];         //字符点阵18字节(显示缓存)
unsigned int m=0,n,i,l=0,p;

//发送一个字节数据给点阵模块
void SendByte( unsigned char dat)
{ unsigned char i;        //循环次数变量
  LED8x8_CLK = 0;_nop_(); //拉低移位时钟
  LED8x8_LAT = 0;_nop_(); //拉低储存时钟
  for( i = 0 ; i < 8 ; i++ ) //循环8次写入一个字节数据
  { if( dat&0x80 ){  LED8x8_DIN = 1; }
    else          {  LED8x8_DIN = 0; }
    LED8x8_CLK = 1;       //上升沿发送数据
    LED8x8_CLK = 0;
    dat <<= 1;      
  }   
}
//主函数入口
void main()
{
  SYS_Init();
  m=0; l=0; n=0;
  //初始化显示缓存
  for(n=0;n<3;n++)           //装入三个字符
  for(i=0;i<6;i++)           //每字六个字节
  { ZF[m]=ASC8[n]; m++; }
  //大循环...
  while(1)   
  { for(p=0;p<8;p++)  {
    for(i=0;i<250;i++) {
    for(m=0;m<8;m++)
    {
      SendByte(TAB[m]);             //列选择                                                                                                                                
      SendByte(ZF[m]);             //行数据(点阵模)
      LED8x8_LAT = 1;_nop_(); //锁存数据
      LED8x8_LAT = 0;_nop_();
    }                } }
    for(i=0;i<18;i++)ZF=ZF[i+1];//18字节左移一位
    l++; NOP10();                   //左移一列           
    if(l>5)
    { l=0;
      for(m=12;m<18;m++){ ZF[m] = ASC8[n][m-6]; }  //加载字符点阵,
      n=n<95?n+1:0;
    } //n=字符编号
  }
}


工程文件, 供初学单片机技术的爱好者参考.
04-8x8点阵LED显示字符串.rar (25.58 KB, 下载次数: 67)

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:381
  • 最近打卡:2025-05-01 08:27:28
已绑定手机

10

主题

146

回帖

458

积分

中级会员

积分
458
发表于 2024-12-9 09:57:52 | 显示全部楼层

必须点赞

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-10 21:05:57 | 显示全部楼层
第五个实验是关于PWM呼吸灯

AI8051U芯片,几乎每个IO口都具有硬件PWM输出功能,使用非常灵活。
本实验将P1口的8个位配置成PWM输出,以实验呼吸灯的效果。
注意,由AI8051U引脚定义图可以看出:
P1.0为PWM1P,P1.1为PWM1N,互为PWM1通道反相互补;
P1.2为PWM2P,P1.3为PWM2N,互为PWM2通道反相互补;

P1.4为PWM3P,P1.5为PWM3N,互为PWM3通道反相互补;
P1.6为PWM4P,P1.7为PWM4N,互为PWM4通道反相互补;
使用相同占空比输出控制时,  交替互为亮灭。


实际效果如视频所示:


主程序

//==============================================================================================
// 文件: Main.C
// 硬件: AI8051U @ 清翔 QX-MCS51 V3.0 学习板
// 功能: AI8051U_32位编程入门初步: 呼吸灯实验
// 端口: P1-8位 LED灯  
// 备注: 下载时选择时钟 11.0592MHZ
// 编程: 浦晓明(浦江一水) 2024-12-09  
//==============================================================================================
#include "AI8051U.H"
#include "AI8051U_SYS.H"


#define Timer0_Reload   (65536UL -(MAIN_Fosc / 1000))  //Timer 0 中断频率, 1000次/秒 1ms中断
#define PWM_PERIOD       1023                          //设置周期值


//全局变量(便于调试观察)
u16 PWM_Duty;   //占空比值
bit PWM_Flag;   //切换标志
//函数说明
void UpdatePwm(void);


//主函数入口
void main()
{
  SYS_Init();
  //定时器0初始化
  AUXR = 0x80;        //定时器0设为1T,16位自动重载
  TH0 = (u8)(Timer0_Reload / 256);
  TL0 = (u8)(Timer0_Reload % 256);
  ET0 = 1;            //定时器0中断使能
  TR0 = 1;            //定时器0启动


  PWMA_CCER1 = 0x00;  //写 CCMRx 前必须先清零 CCxE 关闭通道
  PWMA_CCER2 = 0x00;
  PWMA_CCMR1 = 0x60;  //通道模式配置
  PWMA_CCMR2 = 0x60;
  PWMA_CCMR3 = 0x60;
  PWMA_CCMR4 = 0x60;
  PWMA_CCER1 = 0x55;  //配置通道输出使能和极性
  PWMA_CCER2 = 0x55;


  PWMA_CCMR1 |= 0x08; //开启PWMA_CCR1预转载功能(需要CC1E=1才可写)
  PWMA_CCMR2 |= 0x08;
  PWMA_CCMR3 |= 0x08;
  PWMA_CCMR4 |= 0x08;


  PWMA_ARRH = (u8)(PWM_PERIOD >> 8); //设置周期时间
  PWMA_ARRL = (u8)PWM_PERIOD;


  PWMA_ENO = 0xFF;  //使能输出(8位)
  PWMA_PS  = 0x00;  //高级 PWM 通道输出脚选择位:PWM1_0&PWM2_0&PWM3_0&PWM4_0 //全部指向P1口8位


  PWMA_BKR =  0x80; //使能主输出
  PWMA_CR1 |= 0x81; //使能ARR预装载,开始计时


  EA=1;             //开总中断
  
  while(1);   
}
//定时器0中断服务程序
void timer0() interrupt TMR0_VECTOR   //中断矢量号: 1
{
  if(!PWM_Flag)
  { PWM_Duty++;
    if(PWM_Duty > PWM_PERIOD) PWM_Flag = 1;
  }
  else
  { PWM_Duty--;
    if(PWM_Duty <= 0) PWM_Flag = 0;
  }
  UpdatePwm();
}
//=========================================
// 函数: UpdatePwm(void)
// 描述: 更新PWM占空比.
// 参数: none. 返回: none.
//=========================================
void UpdatePwm(void)
{
    PWMA_CCR1H = (u8)(PWM_Duty >> 8); //设置占空比时间
    PWMA_CCR1L = (u8)(PWM_Duty);
    PWMA_CCR2H = (u8)(PWM_Duty >> 8); //设置占空比时间
    PWMA_CCR2L = (u8)(PWM_Duty);
    PWMA_CCR3H = (u8)(PWM_Duty >> 8); //设置占空比时间
    PWMA_CCR3L = (u8)(PWM_Duty);
    PWMA_CCR4H = (u8)(PWM_Duty >> 8); //设置占空比时间
    PWMA_CCR4L = (u8)(PWM_Duty);
}


//==== END =====================================



工程文件包,供初学单片机的爱好者参考。
06-PWM呼吸灯.rar (23.82 KB, 下载次数: 61)




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-12 08:42:28 | 显示全部楼层
第六个实验是驱动0.96寸OLED单色显示屏
传统的STC89C52开发板,大多配有LCD1602接口。
它的倒序排列是:
GND VCC D7 D6 D5 D4 D3 D2 D1 D0 .....
恰好符合现在市面的一些小屏幕的引脚排列:

GND VCC SCL SDA RST DC CS .....

0.96寸OLED单色屏SS1306四针IIC驱动,分辨率为128*64。

0.96寸OLED单色屏SS1306七针SPI驱动,分辨率为128*64。
都符合这样的排列,因此对实验带来极大的便利。
本例实验是基于七针的OLED屏显示。且看:




主程序

//********************************************************************************
// 名称: Main.C
// 基于: 清翔 QX-MCS51_V3.0 开发学习板
// 实验: OLED 12864 显示屏 SSD1306 驱动
// 编程: 浦晓明(浦江一水) 2024-12-11
//********************************************************************************
#include "AI8051U.H"
#include "AI8051U_SYS.H"
#include "SSD1306.H"
#include "PIC.H"


/** 全局变量说明 设为全局,便于调试观察... **************/
//========================================================================
// 函数: void  delay_ms(unsigned int ms)
// 描述: 毫秒级延时函数。
// 参数: ms,要延时的ms数,自动适应主时钟.
//=====================================================================
void  delay_ms(unsigned int ms)
{ unsigned int i;
  do{ i = MAIN_Fosc / 6000;
      while(--i);
    } while(--ms);
}
/**** 主函数入口 ************************/
void main(void)
{
  SYS_Init();                         //系统初始化
  OLED_Init();                      //初始化
  OLED_CLS();                      //清屏
  OLED_Light(0);                  //最低亮度
  OLED_Light(0xFF);             //最高亮度
  OLED_Light(0xCF);             //初始亮度
  OLED_HZ16(10,3,"单",0,1); //测试汉字
  OLED_HZ16(26,3,"片",0,1);
  OLED_HZ16(42,3,"机",0,1);
  OLED_A16(60,3,'O',0,1);        //测试8*16单字符
  OLED_A08(68,4,'k',0,1);         //测试5*7 单字符
  OLED_String(0,0,"AI8051U",0,1);//测试字符串...
  OLED_Str5x7(10,6,"0123456789ABCD",0,1);
  delay_ms(1000);
  //主循环...
  while(1)
  { OLED_BMP(0,0,128,8,OLED12864_IMG0[0],1); //显式BMP图
    delay_ms(2000);
    OLED_BMP(0,0,128,8,OLED12864_IMG1[0],1); //显式BMP图
    delay_ms(2000);
    OLED_CLS();                                         //清屏
    OLED_String(0,0,"单片机AI8051U",0,1);  //中西文混合显示
    OLED_String(0,2,"单片机AI8051U",1,1);  //正显/反显
    OLED_Str5x7(0,6,"AI8051U",0,1);           //正显
    OLED_Str5x7(0,7,"AI8051U",1,1);           //反显
    delay_ms(2000);
    OLED_CLS();                         //清屏
    OLED_LineH(10,10,108,0);     //画一水平线 作图算法...
    OLED_LineV(10,10,44,0);       //画一垂直线
    OLED_Line(10,10,118,54,0);   //两点一线 不同方向画线...
    OLED_Line(10,54,118,10,0);   //两点一线
    OLED_Line(118,54,118,10,0); //两点一线
    OLED_Line(118,54,10,54,0);   //两点一线
    OLED_Box(0,0,127,63,1);       //画一方框
    OLED_Circle(64,32,30,1);       //画一个圆
    delay_ms(2000);
  }  
}


工程文件包,供初学单片机的爱好者参考。
07-TestOLED1306.rar (43.56 KB, 下载次数: 74)



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-12-13 16:05:44 | 显示全部楼层
第七个实验程序是关于驱动彩色显示屏的


有这么一个小屏,很袖珍,0.96寸的,外形体积与单色OLED相似,但是它却是TFT彩色显示屏。
分辨率是160*80,像素比128*64还多些。价格很便宜,RMB 6.7元。还带一个收藏盒,显得很精致玲珑。
试试看, 用这款传统的清翔QX-MCS51-V3.0开发学习板,来驱动它如何。
微信图片_20241213152346.jpg

由上图可见,其引脚是排列是: GND VCC SCL SDA RST DC CS BLK ,
反过来,插在开发板的LCD1602的排母上,16脚对应GND,15脚对应VCC,就可以了。
经过实践,认识到:
这块显示屏舞动芯片是ST7735S, 经过显示屏厂商的二次开发,变成了模块,具有其一定的特殊性。
屏内的显示缓存,是按照128*160分辨率来设计的,所以显示屏的初始化和使用中,要注意X、Y坐标对应偏移和转换。
反色控制、RGB与BGR的格式切换,寄存器的设置,与手册描述稍有不同。
理论上,这屏旋转四个方向都可以使用的,本实验仅仅将其做成旋转270度横屏方向来使用。(其它方向需要局部修改程序)
实验已经成功驱动显示,其效果图:
微信图片_20241213152405.jpg 微信图片_20241213152413.jpg

微信图片_20241213152421.jpg 微信图片_20241213152435.jpg

其小视频:


主程序:

//===========================================================
// TFT 0.96" 彩色显示屏 160*80 实验程序
// 驱动: ST7735S
// 基于: AI8051U @ 清翔QX-MCS51_V3.0 实验板编程
// 整理:编程: 浦晓明(浦江一水) For 国芯论坛 2024-12-12
//===========================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "AI8051U.h"
#include "AI8051U_SYS.h"
#include "LCD_7735.H"
#include "PIC.H"


unsigned char k;
char S[20];


void Delay1ms(void)        //@22.1184MHz
{ unsigned char data i, j;
  _nop_();_nop_();
  i = 22;        j = 128;
  do
  { while (--j);
  } while (--i);
}
void Delayms(unsigned int count)
{ unsigned int i;
  for(i=0;i<count;i++)      
  Delay1ms();            
}
//主程序入口
void main(void)
{ unsigned char i;
  unsigned int wait=0;
  SYS_Init();
  LCD_Init();
  while(1)
  {  
    for(i=0;i<16;i++)LCD_CLS(i);                  //16色清屏
    LCD_CLS(1);                                          //蓝色清屏
    LCD_H24(2,4,"**单片机**",12,1);           //24点阵中西文混合显示字符串
    LCD_A24(2,30,"A24_Ai8051U",15,1,11);   //显示12*24字符串
    LCD_H16(2,54,"H16_Ai8051U单片机",10,1); //16点阵中西文混合显示字符串
    LCD_A08(2,70,"A08_Ai8051U",15,1,10);    //显示6*8字符串
    Delayms(2000);
    LCD_CLS(4);                                          //暗红色清屏
    LCD_Point(5,5,15);                                 //画点测试
    LCD_LineH(5,5,50,10);                            //画水平线
    LCD_LineV(5,5,50,10);                            //画垂直线
    LCD_Line(5,5,55,55,10);                         //两点一线
    LCD_Box(60,10,80,40,15,0,3);                //画矩形方框(可指定边框色和填充色)
    LCD_A12(2,64,"A12_Ai8051U",10,4,11);  //显示8*12字符串
    Delayms(2000);
    LCD_CLS(0);
    LCD_A16(2,0,"--LCD_ST7735_DEMO.--",10,0,20);
    LCD_BMP(14,16,64,64,P_SET);              //彩色图标显示
    LCD_BMP(82,16,64,64,P_ZER);
    Delayms(2000);
    LCD_CLS(0);
    LCD_A16(2,0,"--LCD_ST7735_DEMO.--",12,0,20);
    LCD_BMP(14,16,64,64,P_XSW);           //彩色图标显示
    LCD_BMP(82,16,64,64,P_SYS);
    Delayms(2000);
    LCD_CLS(0);
    for(i=0;i<16;i++)LCD_Box(i*10, 0,10,40,7,7,i);          //显示彩色条(色号0..15)
    for(i=0;i<16;i++)LCD_Box(i*10,40,10,40,7,7,(unsigned char)(i+16)); //显示彩色条(色号16..31)
    Delayms(2000);
  }
}



工程文件包,供有兴趣的初学单片机爱好者参考。
08-TestLCD7735(80x160).rar (124.3 KB, 下载次数: 80)


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:347
  • 最近打卡:2025-05-01 10:36:23

7

主题

281

回帖

1051

积分

金牌会员

积分
1051
发表于 2024-12-16 17:53:06 | 显示全部楼层
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 20:15 , Processed in 0.137248 second(s), 110 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表