垂柳工作室 发表于 2025-9-22 17:38:07

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。 第六节 学用调试仿真接口7段数码管,温习浮点数存储本节课主要任务是用擎天柱配合烧录工具cdc/hid串口助手,调用7段数码管接口,温习IEEE754标准。一、准备验证工作。拷贝上节课代码,连接擎天柱到电脑上,打开烧录工具,鼠标点击菜单“调试仿真接口”找到并鼠标左键点击打开“接口协议及帮助”,再鼠标左键点击“调试仿真接口”菜单“接口协议及帮助”,鼠标左键点击打开“7段数码管接口”,学习功能3和功能4。二、学用7段数码管接口功能4指令。在数码管上直接显示所给的段码命令格式: STC工程师封装函数名SEG7_ShowCode,可直接调用,函数只有一个参数,是装载数码管8个段状态值的数组。本节课直接调用,配合擎天柱让虚拟数码管显示流动数字。1. 定义变量。在task.c文件中定义一个变量和一个数组:u8 NixieTube_index = 0;u8 NixieTube_code;2. 在task.c文件中定义一个任务回调函数:void Show_NixieTube(void)    {   NixieTube_code = t_display;      if(NixieTube_index + 1 > 9)         {             NixieTube_code = t_display;         }          else          {                NixieTube_code = t_display;            }         if(NixieTube_index + 2 > 9)         {               NixieTube_code = t_display;         }            else          {                NixieTube_code = t_display;             }         if(NixieTube_index + 3 > 9)            {                NixieTube_code = t_display;            }         else            {               NixieTube_code = t_display;         }         if(NixieTube_index + 4 > 9)          {             NixieTube_code = t_display;            }            else            {               NixieTube_code = t_display;            }         if(NixieTube_index + 5 > 9)          {            NixieTube_code = t_display;            }             else             {                   NixieTube_code = t_display;             }             if(NixieTube_index + 6 > 9)            {                NixieTube_code = t_display;         }          else          {            NixieTube_code = t_display;            }          if(NixieTube_index + 7 > 9)          {         NixieTube_code = t_display;         }         else      {            NixieTube_code = t_display;         }         SEG7_ShowCode(NixieTube_code);            if(++NixieTube_index >9)NixieTube_index = 0;}3. 在task.c文件中TASK_COMPONENTS Task_Comps函数内添加一行任务代码:{0, 5000, 5000, Show_NixieTube}4. 在task.h文件中申明一下任务回调函数void Show_NixieTube(void);5. 编译烧录到擎天柱,打开烧录工具CDC/HID串口助手和虚拟数码管,欣赏流水数字。三、温习浮点数存储虚拟数码管功能3使用说明提到了IEEE754格式,有同学问为何3.14159存储数据是40H49H0FHD0H1.单精度浮点数IEEE 754标准存储概述。单精度浮点数在计算机内存中的表示遵循 IEEE 754标准,使用 32位(4字节) 来表示,这32位被划分为三个部分:A、符号位 (Sign): 最高位(第31位),1位。0表示正数,1表示负数。B、指数位 (Exponent): 中间8位(第30位到第23位)。为了能表示负指数,引入了偏移码,其实际值 =无符号整数值-127。C、尾数位 (Fraction/Significand): 最低23位(第22位到第0位)。存储的是小数部分,整数部分的1被隐含,称为“隐含的1”。2.转换计算40H49H0FHD0H第一步:用计算器程序员模式将上述十六进制转换为完整的32位二进制:0100 0000 0100 1001 0000 1111 1101 0000第二步:划分IEEE 754的三个部分符号位 S (第31位): 0 (正数)指数位 Exp (第30-23位): 1000 0000尾数位 Frac (第22-0位): 1001 0010 0001 1111 1010 000第三步:计算指数将指数位Exp: 1000 0000 转换为十进制:128减去偏移量 127:128 - 127 = 1实际指数 E = 1第四步:还原完整的尾数规范化形式的二进制科学计数法有一个隐含的1,将隐含的1和23位尾数位组合起来,完整的尾数 M =1.10010010000111111010000第五步:计算十进制数值计算原理: 数值 = (符号) * (完整尾数M的十进制值) * (2 ^ 指数E)计算完整尾数 M 的十进制值:整数部分: 1 = 1小数部分:1st digit: 1 * (1/2) = 0.52nd digit: 0 * (1/4) = 03rd digit: 0 * (1/8) = 04th digit: 1 * (1/16) = 0.06255th digit: 0 * (1/32) = 06th digit: 0 * (1/64) = 07th digit: 1 * (1/128) = 0.00781258th digit: 0 * (1/256) = 09th digit: 0 * (1/512) = 010th digit: 0 * (1/1024) = 011th digit: 0 * (1/2048) = 012th digit: 1 * (1/4096) = 0.00024414062513th digit: 1 * (1/8192) = 0.000122070312514th digit: 1 * (1/16384) = 0.0000610351562515th digit: 1 * (1/32768) = 0.00003051757812516th digit: 1 * (1/65536) = 0.000015258789062517th digit: 0 * (1/131072) =0.0000076293945312518th digit: 1 * (1/262144) = 019th digit: 1 * (1/524288) =0.000001907348632812520th digit: 0 * (1/1048576) = 021th digit: 1 * (1/2097152) = 022th digit: 0 * (1/4194304) = 022th digit: 0 * (1/8388608) = 0将上述所有值相加1+0.5+0.0625+0.0078125+0.000244140625+0.0001220703125+0.00006103515625+0.000030517578125+0.0000152587890625+0.00000762939453125+0.0000019073486328125=1.57079505920410156251.5707950592041015625×2=3.141590118408203125同学们好学可赞,不过了解一下即可,没必要花太多时间研究。

垂柳工作室 发表于 2025-9-25 15:48:47

新学期伊始,不忘助力国产替代初心,手头没有试验箱,先用“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。 第七节 学用PWM驱动擎天柱LED本节课主要任务是学习PWM相关寄存器及配置产生PWM方波,动态改变方波占空比,驱动擎天柱P2端口LED,展示呼吸效果。一、学习了解PWM相关寄存器芯片手册第二十九章介绍PWM,STC AI8051U内部集成了8通道16位高级PWM定时器,分PWMA和PWMB两组,其中PWMA可配置4组互补/对称STC AI8051U芯片/死区控制的PWM或者捕捉外部信号。PWMB与PWMA唯一区别是PWMA可带死区的互补对称PWM,其他功能一样,所以我们只学习好PWMA即可。PWMA时钟频率可以用系统时钟或外部计时,PWMA时基单元包含,16位计数器、16位自动重载寄存器、重复计数器、预分频器。
其时钟频率是经过设置PWMA_PSCRH和PWMA_PSCRL,进行分频(值1-65535);配置输入输出的引脚寄存器PWMA_ENO;配置PWMA_CCMR1、PWMA_CCER1、PWMA_BKR,打开PWMA_CR1计数,产生PWM信号输出。二、配置PWM相关寄存器1.时钟源选择, 这里选用系统时钟,默认40Mhz2.时基单元选择PWMA_PSCR
//设置周期时间PWMA_ARR
//设置捕获比较寄存器PWMA_CCR//设置占空比时间
3.输入输出的引脚配置//使能PWM1n通道输出PWMA_ENO
//选择PWM从P2引脚输出PWMA_PS擎天柱LED灯接P2端口,所以要配置PWM从P2端口输出
4.输入输出模式设置//配置通道输出使能和极性PWMA_CCER
//通道PWM模式配置PWMA_CCMR
//使能主输出PWMA_BKR = 0X80;
//使能ARR预装载,启动计数器PWMA_CR1
三、定义相关变量和任务函数1. 定义9个变量,4个变量记录占空比,4个记录状态翻转LED灯亮度,1个编辑记录周期。占空比:PWM1_Duty、PWM2_Duty、PWM3_Duty、PWM4_Duty翻转状态:PWM1_Flag、 PWM2_Flag、 PWM3_Flag、PWM4_Flag计数周期:PWM_PERIOD2. 定义一个动态改变占空比函数。void ChangePWM (void){if(!PWM1_Flag)    {      PWM1_Duty++;      if(PWM1_Duty > PWM_PERIOD) PWM1_Flag = 1;    }    else    {      PWM1_Duty--;      if(PWM1_Duty <= 0) PWM1_Flag = 0;    }     if(!PWM2_Flag)    {      PWM2_Duty++;      if(PWM2_Duty > PWM_PERIOD) PWM2_Flag = 1;    }    else    {      PWM2_Duty--;      if(PWM2_Duty <= 0) PWM2_Flag = 0;    }     if(!PWM3_Flag)    {      PWM3_Duty++;      if(PWM3_Duty > PWM_PERIOD) PWM3_Flag = 1;    }    else    {      PWM3_Duty--;      if(PWM3_Duty <= 0) PWM3_Flag = 0;    }     if(!PWM4_Flag)    {      PWM4_Duty++;      if(PWM4_Duty > PWM_PERIOD) PWM4_Flag = 1;    }    else    {      PWM4_Duty--;      if(PWM4_Duty <= 0) PWM4_Flag = 0;    }            PWMA_CCR1H = (u8)(PWM1_Duty >> 8); //设置占空比时间    PWMA_CCR1L = (u8)(PWM1_Duty);    PWMA_CCR2H = (u8)(PWM2_Duty >> 8); //设置占空比时间    PWMA_CCR2L = (u8)(PWM2_Duty);    PWMA_CCR3H = (u8)(PWM3_Duty >> 8); //设置占空比时间    PWMA_CCR3L = (u8)(PWM3_Duty);    PWMA_CCR4H = (u8)(PWM4_Duty >> 8); //设置占空比时间    PWMA_CCR4L = (u8)(PWM4_Duty);}3. 编译烧录拷贝上一节课代码,在task.c文件任务计划函数添加一行:{0,5,5,ChangePWM},为了避免LED亮灯冲突,要注释掉test_Demo中P2=t_display这一行代码。新建一个pwm.c文件和pwm.h文件,并添加到项目中,创建PWM_config初始化函数和ChangePWM任务回调函数。编译烧录,在欣赏过程中,建议捋清楚pwm配置过程,最好按手册中流程图记忆,这样方便日后配置。

垂柳工作室 发表于 2025-10-2 21:15:40

新学期伊始,不忘助力国产替代初心,AI8051U试验箱刚收到,结合“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。 第八节、学用实验箱内芯片74HC595本节课主要任务是学习芯片74HC595,点亮实验箱数码管。一、学习了解移位寄存器74HC5951.芯片概述:74HC595是一款8位CMOS移位寄存器。8位并行输出端口为可控的三态输出,一个串行输出端口,可以实现多级芯片串行控制,组成 8n 位(n 为芯片数量)并行输出。2.芯片管脚定义:管脚1-7和15共8引脚为QA~QH八位数据并行输出端;第八脚GND电源地;第九脚Q′H是串行数据输出管脚;第十脚RESET移位寄存器清零端;第十一脚SCK数据输入时钟端;第十二脚RCK输出存储器锁存时钟端;第十三脚EN输出使能端;第十四脚DATA数据输入端;第十六脚VCC电源端。3.芯片真值表
输入管脚输出管脚
1412111013
SERRCKSCKRESET EN
XXXXHQA~QH 输出端高阻态
XXXXLQA~QH 输出端输出有效值 L 或 H
XXXLL移位寄存器清零, Q'H=0
LX↑HL移位寄存器存储 L 值, Q'H输出 Qn-1
HX↑HL移位寄存器存储 H 值, Q'H输出 Qn-1
XX↓HL移位寄存器状态保持不变
X↑XHL8 位锁存移位寄存器中的状态值并行输出
X↓XHL存储器输出状态保持不变
二、实验箱数码管接法1. 数码管电气连接:实验箱使用两块74HC595芯片,A块74HC595芯片输出接数码管位码,B块74HC595芯片输出接数码管段码(每个数码管abcdefgh合称段码),数据是从A级联到B;所以数据是要先传数码管段码再传位码。
三、实验箱代码学习void Send_595(u8 dat)    //向74HC595芯片发送数据函数{    u8i;    for(i=0; i<8; i++)    {      dat <<= 1;      P_HC595_SER   = CY;//P_HC595_SER = P3^4;芯片第14引脚      P_HC595_SRCLK = 1;//P_HC595_SRCLK = P3^2; 芯片第11引脚      P_HC595_SRCLK = 0;    }}dat <<= 1 左移1位后,被移出去数存在CY寄存器中,P_HC595_SER = CY即数据从14脚输入,根据上面的真值表,可以知道,芯片第11引脚SCK电平上升沿即移位寄存器存储输入数据,超出8位数据从芯片第九引脚输出,级联到下一块74HC595芯片。void DisplayScan(void)//从74HC595芯片读取数据函数{    Send_595(t_display]);   //输出段码    Send_595(~T_COM);             //输出位码    P_HC595_RCLK = 1;//P_HC595_RCLK= P3^5;芯片第12引脚    P_HC595_RCLK = 0;    if(++display_index >= 8)    display_index = 0;    //8位结束回0}实验箱的74HC595芯片A、B第12引脚接在一起,由P3^5统一控制,根据上面的真值表,可以知道,单片机P3^5引脚输出高电平,74HC595芯片A、B输出数码管段码和位码。

垂柳工作室 发表于 2025-10-4 11:56:15

新学期伊始,不忘助力国产替代初心,AI8051U试验箱刚收到,结合“擎天柱”带领大一同学,跟随冲哥视频,学用STC AI8051U芯片讲义。
第九节、学用实验箱NTC测温本节课主要任务是学习NTC测温原理和实验箱17-ADC采集NTC热敏电阻测温度代码。一、学习了解NTC温度传感器   NTC温度传感器是一种热敏电阻、探头,通常由2或3种金属氧化物组成, 混合在类似流体的黏土中,并在高温炉内锻烧成致密的烧结陶瓷。其测温原理为:利用NTC热敏电阻在一定的测量功率下,电阻值随着温度而变化且值是一一对应,利用这一特性, 可将NTC热敏电阻通过测量其电阻值来确定相应的温度,从而达到检测和控制温度的目的。二、实验箱NTC电气连接   实验箱由单片机P51端口给NTC测温电路供电,NTC探头与10K电阻串联,两者的节点连到接线柱,由跳线选择与示波器探头连接ADC3,NTC探头一端接地,如下图所示。NTC测温实际上检测NTC与10K电阻分压,对应单片机12位ADC精度值4096的比值。
三、单片机有关ADC寄存器单片机ADC相关寄存器有时序控制寄存器、转换结果寄存器、ADC配置寄存器、ADC控制寄存器1.ADCTIM //时序控制寄存器      B7   :CSSETUP      //通道选择时间      B6-B5:CSHOLD//通道保持时间      B4-B0:SMPDUTY //信号采样速度,不能小于11个ADC时钟。 2.ADC转换结果寄存器      ADC_RES//高字节      ADC_RESL //低字节3.ADCCFG //ADC配置寄存器      B5: RESFMT //ADC转换结果格式控制,0左对齐、1右对齐      B3-B0: SPEED//ADC工作时钟频率 4.ADC_CONTR//ADC控制寄存器      B7   :ADC_POWER    //ADC电源控制,延长1毫秒让ADC供电稳定      B6   :ADC_START    //ADC转换启动控制      B5   :ADC_FLAG   //ADC转换结束标志,需要软件清除。      B4   :ADC_EPWMT    //使能PWM实时触发ADC功能      B3-B0:ADC_CHS //ADC模拟通道选择   配置流程,先设置时序控制,通道选择和保持时间维持默认值,但信号采样速度,不能小于11个ADC时钟(设置时要大于01010B),建议设置最慢32个时钟(11111B);再配置ADC转换结果格式,常用的是右对齐,转换时间建议设置最慢(1111B)为系统时钟/2/16;接着选择芯片io的ADC采样引脚,并且将io设置高阻模式(昨天我移植学习代码时,就是遗漏了io引脚高阻模式设置,让走了弯路);最后开启ADC电源并延长1毫秒让ADC供电稳定使能ADC。四、源代码学习解析    本章节NTC测温涉及ADC_Config初始化函数,get_temperature计算温度函数和Get_ADC12bitResult采集NTC的ADC值函数,还有一张电阻值与温度对应表u16 code temp_table[];下面对函数关键语句进行解析。void ADC_Config(void)   //ADC初始化函数{    ADCTIM = 0x3f;//设置 ADC 内部时序,ADC采样时间建议设最大值    ADCCFG = 0x2f;//设置 ADC 时钟为系统时钟/2/16/16    ADC_CONTR = 0x80;//使能 ADC 模块}//ADC采集函数u16 Get_ADC12bitResult(u8 channel)//channel为ADC采集通道,值为0到15{    ADC_RES = 0; //清零存储ADC转换值高字节    ADC_RESL = 0; //清零存储ADC转换值低字节    ADC_CONTR = (ADC_CONTR & 0xf0) | channel; //设置ADC转换通道    ADC_START = 1; //启动ADC转换    _nop_();//延时    _nop_();    _nop_();    _nop_();
    while(ADC_FLAG == 0);   //等待转换,ADC转换结束自动将ADC_FLAG标志置1    ADC_FLAG = 0;       //软件清除ADC结束标志    return(((u16)ADC_RES << 8) | ADC_RESL);//返回转换结果,值是16位数}//计算温度函数u16 get_temperature(void){    u16 code *p; //引用电阻值与温度对应表指针    u16 i,adc;    u8j,k,min,max;   adc = Get_ADC12bitResult(3);//实验箱ADC3采集,故参数为3       if(adc < 4096)      {          adc = 4096 - adc;   //由于大咖Coody将NTC温度与阻值对应的ADC值颠倒放置,相当于将NTC电气连接方式倒置,采集的是10k固定电阻分压情况,所以要将4096减去。      p = temp_table; //引用NTC温度与阻值对应表      if(adc < p)      return (0xfffe);//小于表最小值,超量程      if(adc > p)    return (0xffff);//大于表最大值,超量程         min = 0;      //-40度时序号为0      max = 160;      //120度时序号为160
       for(j=0; j<5; j++)//二分折半查询法,缩小范围      {          k = min / 2 + max / 2;         if(adc <= p) max = k;            else            min = k;         }         if(adc == p)i = min * D_SCALE;//         else if(adc == p)i = max * D_SCALE;         else    // adc值为表范围区间值,min < temp < max          {         while(min <= max)//区间范围上下限不相当时            {               min++;//下限逐步累计逼近上限值,比如p累加成p               if(adc == p)   {i = min * D_SCALE; break;}               else if(adc < p)//adc值在表中相邻两档值之间时,即比如表下限p=2048,p=2093,adc=2070情况,下面以此情况解析。                {                  min--;//下限退回,即p变成p                  i = p; //i记录p值,2048/*j记录adc值比p多部分,占p与p之间比值。(adc - i) * D_SCALE:(2070-2048)×10=220;(p - i):2093-2048=45J=220÷45=4.89≈5*/                  j = (adc - i) * D_SCALE / (p - i);                  i = min;//i=65                  i *= D_SCALE; //i=650                  i += j;   //i=650+4.89=654.89≈655                  break;            }          }   }   }return i;}

垂柳工作室 发表于 2025-10-5 14:47:53

新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十节、学用AI8051U串口本节课主要任务是学习AI8051U试验箱代码包“18-P1.3做ADC3-使用ADC15测量内部1.19V信号源,计算外部电压”源代码,学会配置串口寄存器。一、学习了解AI8051U串口概况AI8051U系列单片机具有4个串口通信接口(USART1、USART2、USART3和USART4),其中USART1和USART2是全双工同步/异步串口通信接口,USART3和USART4是全双工异步串口通信接口。每个串行口由2个数据缓冲器、一个移位寄存器、一个串行控制寄存器、一个波特率发生器等组成。每个串行口的数据缓冲器由2个互相独立的接收、发送缓冲器构成,可以同时发送和接收数据。USART1和USART2均有4种工作方式,其中两种方式的波特率是可变的,另两种波特率是固定的。USART3和USART4都有两种工作方式,波特率都是可变的。四个串口通讯口通过功能管脚切换到多组端口,可以实现一个通讯口分时复用为多个通讯口。二、串口寄存器配置步骤1. 功能脚切换。2. 串口工作模式配置。3. 串口波特率发生器选择4. 定时器时钟模式选择5. 定时器计数器寄存器重载6. 定时器控制寄存器使能7. 串口数据寄存器处置8. 串口中断请求标志处置三、学习了解串口寄存器1、串口功能脚切换。P_SW1、P_SW2
2、串口工作模式配置通常配置为可变波特率8位数据方式,即SCON寄存器B7位设置为0,B6位设置为1;实现代码如下:SCON = (SCON & 0x3f) | 0x40;
3、串口波特率发生器选择和定时器时钟模式选择AUXR寄存器B0位值确定波特率发生器,B2、B6、B7定时器速度控制位,如下图。
4、定时器计数寄存器
5、定时器控制寄存器启动
6、串口数据寄存器SBUF、S2BUF
7、串口中断请求标志
上面的寄存器设置,看着很复杂,但作为初学者,建议有必要学习一下,将来实际开发应用时,可直接使用STC的Aicube工具可视化设置,简单、快速、准确。

垂柳工作室 发表于 2025-10-6 19:06:46

新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十一节、学用操作AI8051U内部EEPROM本节课主要任务是学习AI8051U试验箱代码包“19-通过串口发送命令读写EEPROM测试程序”源代码,学习了解AI8051U内部EEPROM。一、学习了解AI8051U内部EEPROM概况Ai8051U系列单片机内部集成了大容量的EEPROM,EEPROM可分为若干扇区,每个扇区512字节,访问EEPROM有IAP和MOV两种方式。IAP方式可以对EEPROM执行读、写、擦出操作,MOV只能对EEPROM进行读操作,不能进行写和擦除操作。EEPROM的写操作智能将字节中的1写0,要将字节中0写为1必须执行扇区擦除操作;EEPROM的读写操作是以1字节为单位进行,每执行一次读或写命令,只能读出或者写入一个字节数据;而擦除操作是以扇区为单位,每个扇区512字节。两种方式访问EEPROM前都需要设置正确的目标地址。EEPROM读、写、擦除操作所需时间不同,但都是硬件自动控制,只需要正确配置IAP_TPS寄存器即可。程序代码只有主循环中或者只有中断代码中使用IAP方式对EEPROM进行操作,则不需要关闭中断;如果主循环代码和中断代码都有使用IAP方式对EEPROM进行操作,那么操作EEPROM时必须关闭中断。二、学习掌握有关EEPROM的寄存器1. EEPROM控制寄存器:IAP_CONTRIAP_CONTR的B7 位IAPEN =1时使能EEPROM操作,B4位CMD_FAIL是失败状态位,此位需要软件清零;B6、B3位是软件复位启动选择;B5位是软件复位触发位。2. EEPROM数据寄存器:IAP_DATA。读操作时,保存读出EEPROM的数据;写操作时,保存写入的数据。3. EEPROM地址寄存器:IAP_ADDR进行读、写、擦除操作的目标地址寄存器。IAP_ADDRH保存地址的高字节,IAP_ADDRL保存地址的低字节。4. EEPROM命令寄存器:IAP_CMDIAP_CMD的B2、B1、B0三位组合确定EEPROM的操作命令。CMD=000(CMD0)为空操作;CMD=001(CMD1)为读字节命令;CMD=010(CMD2)为写字节命令;CMD=011(CMD3)为擦除扇区命令;执行CMD2写字节命令前,必须先将写的数据保存在IAP_DATA中,再发写命令。5. EEPROM触发寄存器:IAP_TRIG设置完成EEPROM读、写、擦除的命令寄存器、地址寄存器、数据寄存器和控制寄存器后,需要向IAP_TRIG先写入5AH再写入A5H命令来触发读、写、擦除操作,而且每次对EEPROM操作都要向IAP_TRIG写入触发命令。操作完成后,EEPROM地址寄存器和命令寄存器内容没变,对下一个目标进行操作时,需要手动更新这些寄存器。6. EEPROM擦除等待控制寄存器:IAP_TPSIAP_TPS=系统工作频率/1000000,小数部分四舍五入进行取整数。三、EEPROM操作数据地址规范EEPROM在64K的flash存储空间中位于FF:C000h---FF:FFFFh。EEPROM总是从后向前规划的,所以无论设置多少,EEPROM在flash存储空间中结束地址始终是FF:FFFFh。使用IAP方式访问,地址数据为EEPROM的目的地址,地址从0000开始,用MOV指令读取EEPROM数据,地址数据为:基地址FF:0000h+程序大小的偏移+EEPROM的目标地址。四、EEPROM操作实现几个函数1、EEPROM命令触发函数:void EEPROM_Trig(void){    F0 = EA;    //F0是程序状态寄存器通用标志,保存全局中断    EA = 0;   //禁止中断, 避免触发命令无效    IAP_TRIG = 0x5A;    IAP_TRIG = 0xA5;        _nop_();   //延迟时间确保IAP_DATA的数据完成准备    _nop_();    _nop_();    _nop_();    EA = F0;    //恢复全局中断}2、EEPROM禁止访问函数void DisableEEPROM(void)      //禁止访问EEPROM{    IAP_CONTR = 0;          //关闭 IAP 功能    IAP_CMD = 0;            //清除命令寄存器    IAP_TRIG = 0;         //清除触发寄存器    IAP_ADDRE = 0xff;       //将地址设置到非 IAP 区域    IAP_ADDRH = 0xff;       //将地址设置到非 IAP 区域    IAP_ADDRL = 0xff;}3、EEPROM使能函数void IAP_ENABLE(void){IAP_CONTR |= 0x80;IAP_TPS = MAIN_Fosc / 1000000;//设置等待时间,要取整数}4、EEPROM读取函数void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u8 length){    IAP_ENABLE();            //使能EEPROM操作    IAP_CMD = 1;             //读EEPROM命令,只需设置一次即可    do    {      IAP_ADDRE = (u8)(EE_address >> 16); //地址高字节      IAP_ADDRH = (u8)(EE_address >> 8);//送地址中字节      IAP_ADDRL = (u8)EE_address;         //送地址低字节      EEPROM_Trig();                      //触发EEPROM操作      *DataAddress = IAP_DATA;            //读出的数据送往      EE_address++;      DataAddress++;    }while(--length);    DisableEEPROM();}EE_address这里是32位数,IAP_ADDRE、IAP_ADDRH、IAP_ADDRL接力存储了1、2、3个字节,最高位第四字节数据没用,单片机是24位寻址机制。5、EEPROM写入函数void EEPROM_write_n(u32 EE_address,u8 *DataAddress,u8 length){ if(length ){      IAP_ENABLE();   //使能EEPROM操作       IAP_CMD = 2;   //字节写命令   do   {         IAP_ADDRE = (u8)(EE_address >> 16); //地址高字节         IAP_ADDRH = (u8)(EE_address >> 8);//地址中字节         IAP_ADDRL = (u8)EE_address;         //地址低字节         IAP_DATA= *DataAddress;         //送数据到IAP_DATA         EEPROM_Trig();                      //触发EEPROM操作         EE_address++;                     //下一个地址         DataAddress++;                      //下一个数据   }while(--length);                     //直到结束DisableEEPROM();}}

垂柳工作室 发表于 4 天前

新学期伊始,不忘助力国产替代初心,带领大一同学,借用AI8051U试验箱和“擎天柱”,跟随冲哥视频,学用STC AI8051U芯片讲义。 第十二节、学用IIC操作AI8051U实验箱内置AT24C02本节课主要任务是学习AI8051U试验箱代码包“28-I2C主机模式访问AT24C02程序”源代码,学习了解IIC总线。一、学习了解IIC总线IIC总线是飞利浦公司推出的一种用于微控制器和外围设备进行通信的串行总线,属于一主多从的总线结构,总线上的每个设备都有一个特定的设备地址,通讯只要两根线,一根数据线SDA,另一根是时钟线SCL,通信都是由主设备发起,从设备被动响应。一般具有IIC总线的元件,其SDA和SCL信号线管脚都是漏极开路输出结构,所以不同器件的SDA与SDA和SCL与SCL之间不需要额外转换电路,可以直接相连,但使用时,SDA和SCL信号线都必须加上拉电阻。二、IIC总线数据传输在IIC总线上,数据是伴随时钟脉冲,由高到低逐位传输,每位数据占用一个时钟脉冲。时钟线SCL高电平期间,SDA线电平高低状态表示传输的数据,高电平为1,低电平为0;传输数据时,SCL为低电平期间,SDA要完成高低电平转换,SCL高电平期间,SDA状态必须保持稳定,否则数据传输会失败。IIC总线数据传输时,包含起始信号、寻址信号、应答信号、传输数据和终止信号。起始信号:SCL为高电平期间,SDA由高电平变成低电平的变化。SCL和SDA高电平要维持大于4.7微秒,再改变SDA为低电平并维持大于4微秒。终止信号:SCL为高电平期间,SDA由低电平向高电平变化,SDA变化前,SCL高电平和SDA低电平维持大于4微秒,SDA由低电平变高电平维持高电平大于4.7微秒。寻址信号:IIC总线约定寻址信号包括从机地址和数据传输方向,即从机地址D7-D1,加上数据传输方向,0表示写(主机传到从机),1表示读(从机到主机);应答信号:IIC总线分应答信号ACK和非应答信号NACK,IIC总线是以字节方式传输数据,发送一个字节后,在时钟的第九个脉冲期间,释放SDA数据线,由接收方发送应答信号,即把SDA电平拉低表示数据接收成功ACK,SDA电平置高表示无应答NACK。SDA电平状态要维持大于4微秒。 三、IIC主设备与从设备通信(1)主设备给从设备发送/写入数据:1. 主设备发送起始(START)信号2. 主设备发送设备地址到从设备3. 等待从设备响应(ACK)4. 主设备发送数据到从设备,一般发送的每个字节数据后会跟着等待接收来自从设备的响应(ACK)5. 数据发送完毕,主设备发送停止(STOP)信号终止传输(2)主设备从从设备接收/读取数据1. 设备发送起始(START)信号2. 主设备发送设备地址到从设备3. 等待从设备响应(ACK)4. 主设备接收来自从设备的数据,一般接收的每个字节数据后会跟着向从设备发送一个响应(ACK)5. 一般接收到最后一个数据后会发送一个无效响应(NACK),然后主设备发送停止(STOP)信号终止传输四、实现IIC总线数据传输函数1. 延时函数:用STC下载工具生成。void Delay5us(void) //@40.000MHz{   unsigned long edata i;   _nop_();   _nop_();_nop_();i = 48UL;while (i) i--;}2. IIC开始void IIC_Start(void) //IIC开始{    SCL = 1; //时钟SCL线拉高    SDA = 1; //通讯线SDA拉高    Delay5us(); //延迟确保时钟SCL线和通讯线SDA高电平超过4.7微秒    SDA = 0; //通讯线SDA拉低    Delay5us(); //延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒SCL = 0; //时钟SCL线拉低Delay5us();}3. IIC结束void IIC_Stop(void)//IIC结束{SCL = 0;SDA = 0;//通讯线SDA拉低Delay5us(); //延迟SCL = 1;//时钟SCL线拉高 Delay5us(); //延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒 SDA = 1;Delay5us(); //延迟确保时钟SCL线和通讯线SDA高电平超过4.7微秒;}4. IIC发送ackvoid IIC_ACK(void){SDA = 0;//通讯线SDA拉低    Delay5us();//延迟    SCL = 1;//时钟SCL线拉高    Delay5us();//延迟确保时钟SCL线高电平期间,通讯线SDA低电平超过4微秒    SCL = 0;//时钟SCL线拉低    Delay5us();//延迟}5. IIC发送NACKvoid IIC_ACK(void){SDA = 1;//通讯线SDA拉高    Delay5us();//延迟    SCL = 1;//时钟SCL线拉高    Delay5us();//延迟确保时钟SCL线高电平期间,通讯线SDA高电平超过4微秒    SCL = 0;//时钟SCL线拉低    Delay5us();//延迟}6. IIC等待从机ACKvoid IIC_WaitACK(void) //等从机回应ACK{SDA = 1;//拉高释放通讯线SDADelay5us();//延迟等待从机相应稳定电平后SCL = 1;//时钟SCL线拉高锁定读取SDA电平,判定从机是否应答Delay5us();//延迟ack = SDA;//读取ACK回应状态Delay5us();//延迟SCL = 0;//拉低时钟SCL完成读取Delay5us();//延迟}7. IIC发送一个字节void IIC_SendByte(u8 dat) //发送一个字节{u8 i;for(i=0;i<8;i++){    if( dat& 0x80 )//1000 0000与dat最高位对比,SDA = 1;    else            SDA = 0;    Delay5us();    SCL = 1;    Delay5us();    SCL = 0;    Delay5us();    dat<<=1;} }8. IIC读取一个字节u8 IIC_ReadByte(void) //读取一个字节{    u8 i=8,dat=0;    SDA = 1;//释放SDA通讯线,以便从机控制SDA。Delay5us();    do    {      SCL = 1;      Delay5us()      dat<<=1;      if( SDA )      dat |= 1;      SCL = 0;      IIC_DELAY();}while(--i); return dat;}9. IIC写入连续的几个字节void IIC_Write_NByte( u8 slave,u8 addr,u8 *p,u8 number ){IIC_START();//开始命令IIC_SENDBYTE(slave);//发送从机地址IIC_WAITACK();//等待从机应答if( !ack )//从机应答ack=0{    IIC_SENDBYTE(addr);//发送数据存储地址,就是表达数据要存哪儿    IIC_WAITACK();//等候从机应答确认收到地址数据    if( !ack )//确认从机收到地址数据ack=0    {   do    {      IIC_SENDBYTE(*p);//发送数组第一个数      p++;//数组指针累加,指向数组下一个数      IIC_WAITACK();//等候从机应答      if( ack )//从机应答失败         break;//推出循环终止写入       }      while(--number);//从机正确应答继续循环写    }}IIC_STOP();//写完释放通信}10. iic读取连续的几个字节void IIC_Read_NByte( u8 slave,u8 addr,u8 *p,u8 number ) {   IIC_START();//开始命令   IIC_SENDBYTE(slave);//发送从机物理电气连接地址   IIC_WAITACK();//等待从机应答   if( !ack )//确认从机应答ack=0   {      IIC_SENDBYTE(addr);//发送数据地址,即从芯片内哪儿读      IIC_WAITACK();//等待从机应答      if( !ack )//确认从机应答在哪个地址读       {          IIC_START();//开始命令          IIC_SENDBYTE((u8)(slave+0x01)); //指令从机输出数据          IIC_WAITACK();//等待从机应答          if( !ack )//从机应答ack=0          {             do             {               *p = IIC_READBYTE(); //P => P               p++;               if( number!=1 )                      IIC_SENDACK();            }            while(--number);             IIC_SENDNACK();            }      }   }   IIC_STOP(); }
页: 1 [2]
查看完整版本: AI8051U单片机学用打卡 | 到这步可直接要 【免费+包邮送】的AI8051U实验箱