gentleman 发表于 2023-8-14 10:22:57

本帖最后由 gentleman 于 2023-8-14 10:24 编辑

2023/08/08 第十集

       汇编一般步骤和基本框架
             规范 有序正确
       一般步骤
             分析 确定算法
             画流程图
             分配资源   RAMTIMERUART等
                   目前主要时外设资源/IO分配问题 ,最好列个表
             写程序
                   .asm
            调试
                   软件模拟
                   在线调试
                        有些问题必须要硬件仿真才能展现
                         软仿永远跟不上硬件的发展
                  
               模块化编程
         框架
         

            
            

         建议不用的中断放复位
         可以提高系统的可靠性
       程序流程图
                 

         典型的例子
            分支
                  JZJNZCJNEDJNZ
                  JCJNCJBJNBJBC
                  
                  自己尝试写一下


                              $NOMOD51
                              $INCLUDE (STC8H.H)
                                       
                              ORG       0000H
                              LJMP      MAIN
                              ORG       0003H

                              MAIN:
                                 MOV SP,#80H
                                 MOV R0,#10; 给R0赋值20H
                                 CLR C
                                 CJNE R0,#37,CMP
                                 MOV R1,0
                                 
                              CMP:
                                 JNC BIG
                                 MOV R1,#0FFH; -1补码0xff
                                 RET

                              BIG:
                                 MOV R1,#1
                                 END



                     


                  

               给R0 赋值10 10<37 得出结果为+1 存入寄存器R1中
               
               老师的例程中使用EQU 定义了SIGN 这个我没有考虑到
                  老师的例程
                  
            

            查表
                  MOVCA,@A+DPTR查找

               MOVDPTR,#SEGTAB       ;移动倒字模表首地址
               MOVA,@A+DPTR         ;查表

                SEGTAB:DB   0C0H         ;子模表
                              DB    0F9H
                                    .
                                    .
                                    .
                               DB   90H
                                 
            循环
                        延时
                           参考stc-isp 生成
                           
                           PUSH/POP 保护/释放 30H/31H
                           DJNZ双重循环

            定点数
                      BCD 减法9AH(100)减去 减数
            
                     
                   多字节乘法
                        

            数据排序
                     冒泡排序

            代码转换
                     A/DD/A BCD 转ascii
                  4BIT二进制转ASCII
                  <10+ 30H
                  >10+ 37H
               
                  

                bcd 转二进制
                低位   R1      个/十   
                高位   R2      百/千
            

               
               
                  
            

             汇编的课程到此应该结束了
             正如老师所说,目前只是掌握了如何去学汇编,而不是掌握了汇编。后面复杂的例程,目前我是无法完成编写的。
             汇编语言的重要性老师都强调过。不管以后是否会用到,感觉还是有必要掌握的。
             汇编的价值不仅仅在程序设计上,更多的是对于底层原理的理解。
             想用单片机,可以不学汇编。想懂单片机,汇编是不可或缺的。
             不管是兼容8051 还是80251 还是arm 指令集(或者哪一天国人搞了一套自研的指令集)单片机的学习,你使用汇编对其底层进行分析,都可以加快对其的理解于掌握。
            
            

gentleman 发表于 2023-8-16 07:18:02

本帖最后由 gentleman 于 2023-8-16 10:30 编辑

2023/08/14第十一集

       c的内容就轻松多了,相信各位都是c语言大神{:4_165:}

      C51 对ANSI C的扩展
            加了19个关键字 常用的有_at_          (这个常用吗?)
                                                sbit            常用于定义引脚
                                                sfr             特殊功能寄存器
                                                bit             位变量
                                                xdata         拓展RAM
                                                code          code FLASH 区域
                                                interrupt   中断

            变量类型
                        新增bit      位型         1bit         0/1
                                  sbit                         1               0/1
                                  sfr                        8               0x80~0xff
                                  sfr16                     8               0x80~0xff


                        bit 不能声明指针 不能做数组
                        sbit 在可独立访问位寻址的位
                        sfr 用来控制定时/计数器 串口 io
                               sfr P0=0x80;
                               sbit cy=psw^7
            内存区域的制定
                      code常数,可用于保存数码管码表
                      RAM
                           data   直接寻址低 128 BYTE
                           idata间接寻址RAM 256 BYTE
                           bdata位寻址   20H~FH
            外部数据存储器
                           xdata外部RAM 大数组可用,
                           pdata    别用!!! 8032时代选页的,pdata与xdata有冲突
            指针
                     一般和ANSI C一样
                     很重要,很灵活      
                     硬件相关寄存器指针需要使用volatile 保证不被优化
                     例
#define P0PU (*(unsigned char volatile xdata *)0xfe10)
            中断
                  声明
                     
void UART_ISR(void) interrupt 4
{
       //中断服务程序代码
}                     使用中断号 说明哪个中断

               加using 指定工作寄存器区
               加small/large 说明存储模式            

      c的运算
                     算数运算
            
                  逻辑运算
                      &&||!
                   不太认同老师说的 !不常用,感觉!还是很常用的,我经常写 if(!a) 而不是 if(a==0);
                  位运算符
                  & |^~ << >>
                  &类似 ANL
                  |   常用于 给莫一位置1psw2 |=0x80最高位置1
                  <<      RLC
                  >>      RRC

      STC8H C51 框架
            #inlcude "stc8h.h"
void delay(long delaytime)
void main(void)
{
      while(1)
   {
          delay(100);
      }
}



      

gentleman 发表于 2023-8-16 10:29:39

2023/08/14 第十二集

      c语言程序设计实例
      例1 闪灯程序
            stc8h.h 没必要拷贝


                        #include <stc8h.h>


                        void Delay500ms();
                        void main(void)
                        {
                                P4M0= 0x00;
                                P4M1= 0x00;
                                P6M0= 0x00;
                                P6M1= 0x00;
                                P4 = 0;
                                while(1)
                                {
                                        P60=1;
                                        Delay500ms();
                                        P60=1;
                                        Delay500ms();
                                }
                        }


                        void Delay500ms()                //@11.0592MHz
                        {
                                unsigned char data i, j, k;


                                i = 29;
                                j = 14;
                                k = 54;
                                do
                                {
                                        do
                                        {
                                                while (--k);
                                        } while (--j);
                                } while (--i);
                        }
         

            注意 这里do while在编译器被翻译为DJNE 便于计算循环次数
                            while 被翻译为 CJNE于 SJMP   由于存在 是否跳转的问题不容易计算
                     
                           使用 data 强制定义数据区域,避免编译器设为large 等影响延时时间
      
                使用移位可以简单的实现流水灯/跑马灯
                定义变量
                     LEDdata = 0x01;
               在主循环中左移
                     LEDdata <<= 1;
               判断
                     if(!LEDdata)
                           LEDdata = 0x01;
               给IO赋值   
                     P6 = LEDdata;
               
          例2 flash操作

                                #include <stc8h.h>
                                #include "intrins.h"


                                void IapIdle()
                                {
                                        IAP_CONTR = 0;
                                        IAP_CMD = 0;
                                        IAP_TRIG = 0;
                                        IAP_ADDRH = 0x80;
                                        IAP_ADDRL = 0;
                                       
                                }


                                char IapRead(int addr)
                                {
                                                char dat;                     


                                                IAP_CONTR = 0x80;               //使能IAP
                                                IAP_CMD = 1;                  //设置IAP命令
                                                IAP_ADDRL = addr;               //设置IAP低地址
                                                IAP_ADDRH = addr >> 8;          //设置IAP高地址
                                                IAP_TRIG = 0x5a;                //写触发命令(0x5a)
                                                IAP_TRIG = 0xa5;                //写触发命令(0xa5)
                                                _nop_();                        //等待ISP/IAP/EEPROM操作完成
                                                dat = IAP_DATA;               //读ISP/IAP/EEPROM数据
                                                IapIdle();                      //关闭IAP功能


                                                return dat;                     //返回
                                }


                                void IapProgram(int addr, char dat)
                                {
                                                IAP_CONTR = 0x80;               //使能IAP
                                                IAP_CMD = 2;                  //设置IAP命令
                                                IAP_ADDRL = addr;               //设置IAP低地址
                                                IAP_ADDRH = addr >> 8;          //设置IAP高地址
                                                IAP_DATA = dat;               //写ISP/IAP/EEPROM数据
                                                IAP_TRIG = 0x5a;                //写触发命令(0x5a)
                                                IAP_TRIG = 0xa5;                //写触发命令(0xa5)
                                                _nop_();                        //等待ISP/IAP/EEPROM操作完成
                                                IapIdle();
                                }


                                void IapErase(int addr)
                                {
                                                IAP_CONTR = 0x80;               //使能IAP
                                                IAP_CMD = 3;                  //设置IAP命令
                                                IAP_ADDRL = addr;               //设置IAP低地址
                                                IAP_ADDRH = addr >> 8;          //设置IAP高地址
                                                IAP_TRIG = 0x5a;                //写触发命令(0x5a)
                                                IAP_TRIG = 0xa5;                //写触发命令(0xa5)
                                                _nop_();                        //等待ISP/IAP/EEPROM操作完成
                                                IapIdle();
                                }


                                void main()
                                {
                                        unsigned char dataread=0,datawrite=0;
                                       
                                        IapErase(0x0400);
                                        dataread = IapRead(0x400);
                                        IapProgram(0x400,0x12);
                                        datawrite = IapRead(0x400);
                                       
                                        while(1);
                                }   
               


                      基本的eeprom 操作,在需要掉电存储的场合下很常用。 而且不需要外挂24/25系列存储器,易用性于安全性都有很大提升   
               放在这里应该是让大家熟悉一下寄存器的操作。
                        记得写eeprom之前要先擦除,每次擦一个扇区。
                        这里没有判断LVDS,有些场合需要判断,保证低压时不要进行eeprom操作。


                              

gentleman 发表于 2023-8-21 06:56:18

2023/08/16 第十三集
      中断
            单片机执行其他程序 , 出现某些异常事件或请求,cpu 中止,转去执行异常事件,执行完毕,返回继续执行。
      中断源
            cpu中断请求源
      中断响应
            cpu暂停工作转去处理中断源事件
      中断服务
               处理工程
         中断返回
               处理完返回中断的地方
         中断优先级
               
                低优先级会挂起LCALL
         保护现场
               PUSHPOP 指令 堆栈操作实现
         堆栈
               先进后出
               SP 指向栈顶
            中断撤除
                中断请求标志位擦除,有的会自己擦除
            中断源
               stc8h44个
               

         
               

            

             注意 中断号是keil 的c51
                     查询次序是8051的 先有查询次序
      中断标志位
             TCON
                  IT0       触发方式   0上升/下降沿触发      
                                             1   仅下降沿触发
                  IE0      INT0 请求标志
                  IT1      INT1 触发方式
                  IE1      INT1请求标志
            AUXINTIF
                  管定时器2~4的
                   所有定时器外部中断标志位自动清0
            串口
               TI/(SX)TI    RI/(SX)RI
               不能自动请0
               
               可以直接写TI=0 ,因为地址可以被8整除
   
               

gentleman 发表于 2023-8-21 07:16:49

本帖最后由 gentleman 于 2023-8-21 07:48 编辑

2023/08/16 第十四集
         中断标志位
               PCON
                   LVDF   低电压检测 不开中断也可以读
               SPI
                   SPSTAT 传输完成置位
               ADC
                   ADC_CONTR   A/D转换结束标志位
                                        需要软件清0
          中断允许,禁止,优先级
          IE 0A8H
      
               EA总中断
                     0关闭
                     1开放
                ELVD 低压检测
                EADC A/D
                ES   串口1
                ET1    定时器1
                EX1    INT1
                ET0    T0
                EX0    INT0
         优先级
               
                  00 01 1011对应1234 级
                  先高后低 停低转高 高不睬低
               
                  即使关闭EA/分中断开关 标志位也改变,只是不响应,可以查
         
                  RETI 不能写成RET 结果只执行一次


         不响应中断的情况
               EA/   不开不响应
                  cpu执行更高一级的中断
                  执行的机器周期不是指令周期的最后一个机器周期
                  执行的是RETI 或 访问IP/IPcpu再执行一条指令才响应中断
          终端服务
                入口 到 RETI

               保护现场   终端服务恢复现场中断返回

               中断可以临时关。避免高优先级中断   

                实例:通过INT0 改变灯状态

                        基于原来的点灯程序修改


                        IT0 =1;
                     EX0 =1;
                        EA=1;
                        
                      这样中断1和总中断就打开了

                     再写个中断函数,把引脚取反

                     void INT0_ISR interrupt中断号忘了,好像是0
                     {
                           P60=~P60;
                     }

                        INT0 放个小电阻 100R或者300R 保护一下


                        用汇编写要在头部写好外部中断的跳转地址
                        ORG 0003H
                        LJMP INT0_ISR
                        
                         给开关置0,选触发模式
                         SETB IT0
                         SETB EX0
                         SETB EA
                        
                        在最后写上中断子程序

                        INT0_ISR:
                                  CPI P6.0
                                  RETI
                                  END


          中断在程序设计中是很常用的。基本稍微复杂一点的程序就会用到。
          如果没有中断,cpu就只能靠轮询。对程序设计的影响还是很大的。
          stc8/32 相对于传统8051添加了很多中断,更加简化了对程序的设计。
          比如原来的定时器就经常不够用,要用其他的方式去处理,stc的有4~5个,还能自动重载,随便用。

gentleman 发表于 2023-8-27 08:38:40

2023/08/27 第 15 集
      定时器结构
               功能 : 定时或计数
                           分频
                           可编程输出
                           串口波特率发生器

             一般结构   

            系统/外部来的时钟 让计数器加1 加满了就中断      

               

               

               

               工作模式 4种
                         常用16位自动重载/不可中断的16位自动重载


               下图是模式0 16位自动重载
                非常清晰,图看懂了,就会用定时器了。
               


                T2 模式固定 16位自动重载
                        
                寄存器不用背 会查就行   

      定时器寄存器
            TMOD
                         GATEC/TM1M0    GATEC/T   M1M0
                  
                            M1M0   
                            0      0          模式0 16位自动重载
                            1      1          模式3 最高中断优先级的16位自动重载
      
                                 记住这两个模式就行

                            C/T      1 计数器
                                       0 定时器
                            GATE   1~INTn搞 且 TRn置位 启动
                                    0   TRn 置位 启动
            TCON

                         TF1TR1 TF0TR0IE1IT1IE0IT0

                         TF1/0       中断标志位 自动清
                        
                         TR1/0      开关 置1启动

                         后面4位是外部中断的
            
            AUXR
                         T0x12T1x12UART_M0x6T2RT2_C/TT2x12EXTRAMS1T2
                        
                         T0x12/T1x12   0 12分频
                                             1 不分频
                        TR2                定时器 2开关 置1启动
                        T2_C/T            0T2 12个时钟计数1次
                                                1   T21个时钟计数1次
                        UART_M0x6   串口速度
                           S1ST2            波特率发生器选择位
             T4T3M
                         T4RT4_C/T    T4x12T4CLKOT3RT3_C/TT3x12T3CLKO
                        
                        T4/T3CLKO时钟输出开关置1开启
                        其他参考上面
                        
                        

gentleman 发表于 2023-8-27 08:58:43

2023/08/21第16集
         定时器应用

            最大能力
                  fosc = 11.0592m
                  12分频

                     1计数周期 = 12/晶振频率-12/110592 =1us

                     N = M-TC/TP

                     TC/TP = 1000;

                     T = 71.111ms

               T2/T4
                  T = 18s

          量程拓展
                一般用软件
                     多次中断后处理一次时间就行
            
          例程
                  汇编例程看的懂就好,也不太复杂
                  后面再尝试写。

                  c:

void Timer0_Isr(void) interrupt 1


{
       i--;
       if(!i)
      {
                P60 = ~P60;
                i = 0;
         }
}

void Timer0_Init(void)                //50微秒@11.0592MHz
{
        AUXR |= 0x80;                        //定时器时钟1T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0xD7;                                //设置定时初始值
        TH0 = 0xFD;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
      EA = 1;
}


   然后再main 调用初始化函数 就行了

   记得设置
               PXMX = 0x00;
               P40 =0;

   运行程序就会看到 试验箱的灯在闪 500ms 亮一次

    后面还有操作其他定时器的例程

    注意T2 T3 T4 的许多寄存器都不能位寻址

    定时器是很常用的应用,大家一定要多多练习

                        
            

gentleman 发表于 2023-9-3 11:49:30

2023/08/23第十七集

       STC8H8K64U
         4 UART
         1 SPI
         1 I2C
         1 USB
      
       并行 -同时传送
       串行 -一位移位传脉冲
            
    TTL<10M
    RS232 15M
    RS485 100M多机

    异步通讯0/1 作为字符标志
         

         约定编码形式 奇偶校验 起始位停止位
                  通讯速率9600,n,8,1


            单工/半双工 / 全双工

      串行接口的内部结构
      

   

    时序图

   

    stc补充多机通信
               




gentleman 发表于 2023-9-3 11:58:19

2023/08/23 第十八集
         STC8H8K64U
         4个串口全双工 支持DMA
            
         两个SBUF独立


         SFR


      

      SCON
      

       常用模式1 3

    工作模式1示意图
      
      

    可以由定时器作为波特率发生器
   
   



   

gentleman 发表于 2023-9-3 12:09:11

2023/08/28 第十九集

       使用定时器作为波特率发生器时要 TR1/TR2=1
       中断不用开

   

   常用stc-isp 工具计算定时器初值

    实时任务需要 中断

   编程要点
         SCON 设置
         TMOD/SMOD 设置
         ES/EA 设置
         data -> SBUF
          清TR/RI 编程序

          其他串口类似,注意寄存器不同

    流程图

      发送
      


       接收

      
   


      注意波特率要相同,才能进行通信

多机通信

                SM2 标志位区分

   流程图
         

      注意TB8=1   发地址
         发完清TB8

   

   
         
      
页: 1 [2] 3 4
查看完整版本: 【实验箱已收到】陈老师《单片机原理及应用-STC8H8K64U》打卡 | 实验箱已收到