找回密码
 立即注册
查看: 1038|回复: 11

好书推荐《51单片机轻松入门—基于STC15W4K系列》

[复制链接]
  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
    发表于 2023-4-29 13:21:30 | 显示全部楼层 |阅读模式
    温故知新 - 先学这个STC15W4K系列。



    李先生坚持了这么多年,终于公开了本书,不容易! 谢了!
    《51单片机轻松入门 基于STC15W4K系列》429页 84.1M高清书签电子版

    配套视频与例程地址
    百度网盘视频与光盘地址:

    https://pan.baidu.com/s/1fb1ymPDqMVpKYPqZDOjKvg 提取码:ef2w

    好书推荐《51单片机轻松入门—基于STC15W4K系列》
    强烈推荐单片机顶级好书,此书的编写建立在作者十多年的产品研发经验基础之上,又经历了大约5年的精心编写整理时间,每一章都是实际运用中非常重要的精华知识,如果您是单片机初学者或对单片机已经学会了些皮毛,毫不吹牛,这本书绝对是您不能当面错过的学习与产品研发的顶级参考资料,因为这些知识都来源于实践,是花费了大量时间和金钱换来的,内容真实不虚。特别对串口通信、SPI通信、I2C通信等作了完整透彻的分析。全书大量的经典电路可以照搬,大量的代码直接复制粘贴就可以正常使用,可为读者减少很多的工作量。全书以当今最新主流的STC15W4K系列单片机进行介绍与实验,并配套了辅助参考视频,提供作者邮箱答疑、QQ在线答疑、国内知名网站单片机论坛答疑。
    2021年视频下载地址
    《51单片机轻松入门 基于STC15W4K系列》.jpg

    QQ群(STC51-STM32): 99794374  ,验证:STC15单片机。 邮箱:xgliyouquan@126.com
    此书于2015年6月已出版。读者评论:
    内 容 简 介
    本书以最新流行的不需要外部晶振与复位电路的可仿真的高速STC15系列单片机为核心,详细介绍了
    单片机内部功能模块,比如定时器、中断、串口、SPI接口、片内比较器、ADC转换器、可编程计数器阵列
    (CCP/PCA/PWM)等。每个重要知识点都有简短精炼的实例作验证,然后就是单片机常用外围接口的介绍与
    STC15系列单片机的实际产品运用实例分析。另外对单片机开发必须掌握的C语言基础知识与Keil开发环
    境也作了较为详细的介绍,对于没有学习过C语言的读者通过本书也能轻松进入以C语言开发单片机的学
    习状态。
    为了快速验证本书的理论知识,作者设计了与本书配套的双核(两个仿真型单片机)实验板,功能强
    大,操作简单,直观,除用于本书实验测试外,也可用于产品前期开发。
    本书可作为普通高校计算机类、电子类、自动控制类、仪器仪表类、机电一体化类等相关专业教学用书,
    对已有一定设计经验的单片机工程师也有重要参考价值。

    目录如下
    第1章  单片机高效入门
    1.1  单片机简介
    1.1.1 认识单片机
    1.1.2 单片机的用途
    1.1.3 学习的典型芯片与C语言介绍
    1.1.4 本书配套实验板及相关学习工具介绍
    1.2 点亮1个发光二极管   
    1.2.1  单片机型号命名规则
    1.2.2  单片机引脚功能说明   
    1.2.3 制作一个最简单的单片机实验电路
    1.2.4 使用Keil uVsion3环境编写最简单的程序
    1.2.5 ISP下载程序到单片机(将电脑上的目标代码“灌入”单片机中运行)
    1.2.6 程序解释
    1.3 Keil 仿真  
    1.3.1 软件仿真(标准8051方式仿真,不能仿真单片机新增功能)
    1.3.2 硬件仿真(利用STC专用仿真芯片仿真,可仿真所有功能)
    1.4 经典流水灯实例
    1.5  单片机C语言延时程序详解
      1.5.1 学会使用计算软件
      1.5.2 计算软件内部运算过程详解
      1.5.3 利用库函数实现短暂精确延时
    1.5.4 使用定时器/计数器实现精确延时
    1.6  main()、void main()和int main()的区别
    1.7  printf 格式化输出函数
    第2章  单片机开发必须掌握的C语言基础
    2.1 简单数据类型与运算符
    2.1.1  原码、反码、补码、BCD码、格雷码
        2.1.2  常量      
        2.1.3  变量的数据类型(bit、char、int、long、float)
    2.1.4  变量存储空间(code、data 、bdata 、idata、xdata)
    2.1.5  变量存储类型(auto、static、extern)
    2.1.6  变量作用域
    2.1.7  运算符   
    2.1.8  运算符的优先级与结合性
    2.2 C51构造数据类型
    2.2.1 数组:将相同类型数据组合在一起就构成数组(如数码管显示缓冲区)
    2.2.2 结构体:将不同类型数据组合在一起就构成结构体(如年月日2014-12-31)
    2.2.3 共用体:不同变量占用相同内存地址就是共用体
    2.2.4  指针:用于直接读取或修改内存值
    2.2.5  #define与typedef的差别
    2.3 流程与控制
    2.3.1  分支结构
      2.3.2  循环结构
      2.3.3  跳转结构
    2.4  函数
        2.4.1  函数定义
    2.4.2  调用格式
    2.4.3  传值调用与传地址调用2种方式对比
    2.4.4  数组作为函数参数
    2.4.5  使用指针变量作函数形式参数
    2.4.6  使用结构体变量指针作为函数参数
    2.4.7  函数作用域
    2.4.8  库函数
    2.5  模块化编程
    2.5.1  头文件的编写
        2.5.2  条件编译
    2.5.3  多文件程序(模块化编程)
    第3章  定时器/计数器、中断系统   
    3.1 定时器/计数器
    3.1.1 单片机定时器/计数器工作原理概述
    3.1.2 定时器/计数器的相关寄存器   
    3.1.3 定时器/计数器的工作方式     
    3.1.4 初值计算
    3.1.5 编程举例
    3.2 可编程时钟输出
    3.3 中断系统
    3.3.1 中断系统结构图
    3.3.2 操作电路图中的开关(相关寄存器介绍)
    3.3.3 编写中断函数
    3.3.4 中断程序举例
    3.3.5 外中断代码调试(按键的防抖技术)
    第4章  串口通信
    4.1  最基本的串口通信
    4.1.1  串口数据发送格式
    4.1.2  串口相关寄存器
    4.1.3  波特率计算步骤详解
    4.1.4  单片机与计算机通信的简单例子
    4.2  彻底理解串口通信协议           
    4.3  串口隔离电路
    4.4  计算机扩展串口(USB 转串口芯片CH340G)
    4.5  RS485串行通信
    4.6  SSI通信
    4.6.1  SSI数据通信格式
    4.6.2  SSI硬件电路
    4.6.3  SSI软件实现
    4.7 数据通信中的错误校验
    4.7.1 校验和(CheckSum)与重要的串口通信实例  
    4.7.2 CRC校验(全称:循环冗余码校验)        
    4.8  单片机串口向计算机串口发送2进制、16进制、数值与字符串              
    第5章  SPI通信
    5.1  SPI总线数据传输格式       
    5.1.1  接口定义
    5.1.2  传输格式
    5.2  SPI接口相关寄存器
    5.2.1  SPI相关的特殊功能寄存器  
    5.2.2  SPI接口引脚切换
    5.3  SPI接口运用举例
    第6章  I2C通信
    6.1  I2C总线数据传输格式  
    6.1.1  各个位的传输要求   
      6.1.2  多字节传输格式     
    6.2  程序模块功能测试      
    6.2.1 硬件仿真观察24C02读写结果(R/C时钟:22.1184MHz)
    6.2.2  硬件仿真观察24C32/64读写结果(R/C时钟:22.1184MHz)
    6.3  24C02运用实例(断电瞬间存储整数或浮点数)         
    第7章  单片机内部比较器与DataFlash存储器  
    7.1  STC15W系列单片机内部比较器
    7.1.1  比较器结构图
    7.1.2  寄存器说明
    7.1.3  电路讲解与程序实例
    7.2  DataFlash存储器     
    7.2.1 DataFlash操作有关的寄存器介绍
    7.2.2  DataFlash操作实例(断电瞬间存储数据)
    第8章  可编程计数阵列CCP/PCA/PWM模块(可用作DAC)
    8.1  PCA模块总体结构图
    8.2  PCA模块的特殊功能寄存器
    8.3  PCA模块的工作模式与应用举例
    第9章  模数转换器ADC
    9.1  模数转换器ADC主要技术指标
    9.2  使用单片机内部的10位ADC转换器
    9.2.1、ADC相关的特殊功能寄存器
    9.2.2、实例代码
    9.3  12位ADC转换芯片MCP3202-B
    9.4  16位ADC转换芯片ADS1110A0
    9.5  18位ADC转换芯片MCP3421A0T-E/CH
    第10章  数模转换器DAC
    10.1  TLC5615数模转换电路与基本测试程序
    10.2  TLC5615产生锯齿波、正弦波、三角波
    10.3  TLC5615的高级运用(播放歌曲)
    第11章  单片机实用小知识
    11.1  复位
    11.1.1  外部RST引脚复位
    11.1.2  软件复位
    11.1.3  内部低压检测复位
    11.1.4  看门狗定时器复位
    11.2  单片机的低功耗设计
    11.2.1  相关寄存器说明
    11.2.2  应用举例
    11.3  单片机扩展32K外部数据存储器62256
    11.3.1  电路讲解
    11.3.2  软件测试实例
    第12章  常用单片机接口程序  
    12.1  数码管静态显示
    12.2  数码管动态显示
    12.3  独立键盘
    12.4  矩阵键盘
    第13章  1602液晶
    13.1 1602液晶外形与电路图
    13.2 1602液晶运用举例
    13.3 1602液晶显示汉字与特殊符号
    第14章  精密电压表\电流表\通用显示器\计数器制作
    14.1  功能说明与电路原理分析
    14.2  程序实例
    14.2.1  通用显示器功能检测程序(外部程序)
    14.2.2  计数器功能检测程序(外部程序)
    14.2.3  模块程序
    第15章  步进电机测试
    15.1  步进电机特点
    15.2  步进电机的3种励磁方式
    15.3  步进电机驱动电路
    15.4  步进电机驱动实例
    15.5  步进电机专用驱动器介绍
    第16章  频率检测
    16.1  频率检测的用途与频率定义
    16.2  频率检测实例
    第17章  DS1302时钟芯片
    17.1  DS1302的SPI数据通信格式
    17.2  程序实例
    第18章  红外通信   
    18.1  红外通信电路与基本原理
    18.2 红外接收软件实例
    第19章  单总线DS18B20 通信(长距离无线通信)
    19.1 DS18B20运用基础
         19.1.1  单只DS18B20温度检测电路
         19.1.2  DS18B20通信时序
         19.1.3  DS18B20内部功能部件ROM、RAM、E2RAM、指令集
       19.1.4  读取温度步骤
    19.2  单只DS18B20的温度检测实例
    19.3  多只DS18B20的温度检测
         19.3.1  读取传感器代码实例
    19.3.2 读取传感器温度实例
    第20章  SD卡与znFAT文件系统
    20.1  认识SD卡与SD卡驱动程序
    20.1.1  认识SD卡
    20.1.2  电路讲解
    20.1.3  通信时序与完整驱动程序说明
    20.2  znFAT文件系统
    20.2.1  znFAT的移植方法
    20.2.2  znFAT移植实例
    第21章  MP3播放器实验(znFAT文件系统运用实例)
    21.1  MP3介绍与电路讲解
    21.2  正弦测试
    21.3  通过SD卡播放MP3文件
    第22章  数字存储示波器技巧与逻辑分析仪的操作
    22.1  测量直流电源开关机瞬间输出毛剌浪涌
    22.2  测量稍纵即逝的红外发射信号
    22.3  精确测量直流电源纹波
    22.4  示波器带宽选用依据
    22.5  逻辑分析仪快速入门
    附录   ASCII码表

    参   考   文   献

    很多人问,零基础是否能学懂我的书,我只能说,如果小学都没毕业的人,肯定是光脑壳打阳尘——莫望,学习我的书需要有电路基础知识(至少认识常见的电子元件,比如电阻、电容、二极管、三极管等,能看懂简单的电路图),还必须有对单片机的浓厚兴趣。

    纸版书408页,阅读纸版不存在电脑辐射问题,还方便在上面作笔记,如果学真正学透单片机,建议购买纸版。



    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2023-4-29 19:50:14 | 显示全部楼层
    欢迎指出错误或提出问题。此例为例程解释的一点错误,请以红色说明文字为准。书上193页说明:每一位的写入是用时钟上升沿同步数据,也就是说时钟上升沿后从器件(指24C02)开始检测输入的数据,每一位的读取是用时钟下降沿同步数据,也就是说时钟下降沿后从器件开始输出数据。
    下面是例程代码。
    //*********************************************************************

    // 功能描述:主设备向从设备发送个一字节
    // 返回值: 0->成功  1->失败
    //*********************************************************************/
    unsigned char IIC_SendByte(unsigned char Data)   
    {
            unsigned char i;               // 位数控制
            for (i=0;i<8;i++)           // 写入时是用时钟上升沿同步数据
            {
                    if (Data & 0x80)
                            SDA = 1;
            else
                            SDA = 0;
            delay(tt);                   // 保持0.2uS以上(TSU.DAT)
            SCL = 1;
                    delay(tt);                   // 保持4.0uS以上(THIGH)
                    SCL = 0;
                    delay(tt);                  // 保持4.7uS以上(TLOW)
            Data <<= 1;
             }      
             return IIC_GetACK();  
    }

    //*********************************************************************
    // 功能描述:主设备向从设备读取一个字节
    // 返回值:  读到的字节  
    // *********************************************************************/
    unsigned char IIC_RecByte(void)       // 接收单字节的数据,并返回该字节值
    {
            unsigned char i,rbyte=0;
            SDA=1;
            for(i=0;i<8;i++)                  // 读出时是用时钟下降沿同步数据
            {
                    SCL=0;
                    delay(tt);                          // 保持4.7uS以上(TLOW)
                    SCL=1;
                    delay(tt);                          // 保持4.0uS以上(THIGH)
                    if(SDA) rbyte|=(0x80>>i);
            }
            SCL=0;
            return rbyte;
    }
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2023-5-2 08:35:59 | 显示全部楼层
    本帖最后由 angmall 于 2023-5-2 08:40 编辑

    《51单片机轻松入门-基于STC15W4K系列》一个单片机内两串口互相通信,串口1发送数据给串口2,串口2根据收到的数据控制led的亮灭,怎么实现呢?

    221207tgjba1brhd4kng1k.png

    这个例子书上没有,只能给现写一个了。程序功能:单片机串口1发送0-255范围内不断增大的数,串口2接收到数据后送PO口LED显示,已在实验板上验证通过。


    串口1与串口2使用2条杜邦线连接即可,实验结果如下图所示。

    我还有个问题,就是串口的工作方式换成1,2,3都可以实现这个两串口间的通信吗?

    串口1 支持的工作方式 0、1,2,3,串口2、3、4只支持10位与11位串口通信方式。相当于没有串口1的方式0和方式2,实际上串口1的方式0和方式2可看着多余的,没什么用。

    1. #include "STC15W4K.H"      // 包含 "STC15W4K.H"寄存器定义头文件
    2. void delay500ms(void)
    3. {
    4.    unsigned char i,j,k;
    5.    for(i=93;i>0;i--)       // 注意后面没分号
    6.    for(j=235;j>0;j--)      // 注意后面没分号
    7.    for(k=125;k>0;k--);     // 注意后面有分号
    8. }
    9. void UART_init(void)
    10. {                  
    11.     //下面代码设置定时器1
    12.     TMOD = 0x20;        // 0010 0000 定时器1工作于方式2(8位自动重装方式)
    13.     TH1  = 0xFA;        // 波特率:9600 /22.1184MHZ
    14.     TL1  = 0xFA;        // 波特率:9600 /22.1184MHZ
    15.     TR1  = 1;
    16.     //下面代码设置定串口
    17.     AUXR = 0x00;             // 很关键,使用定时器1作为波特率发生器,S1ST2=0
    18.     SCON = 0x50;         // 0101 0000 SM0.SM1=01(最普遍的8位通信),REN=1(允许接收)
    19. }
    20. void UART_send_byte(unsigned  char dat)
    21. {
    22.     SBUF = dat;
    23.     while(!TI);            
    24.     TI=0;         //此句可以不要,不影响后面数据的发送,只供代码查询数据是否发送完成
    25. }
    26. void UART2_init(void)
    27. {                  
    28.     // 下面代码设置定时器2
    29.     T2H  = 0xFD;        // 波特率:9600 /22.1184MHZ,1T
    30.     T2L  = 0xC0;        // 波特率:9600 /22.1184MHZ,1T
    31.     AUXR = 0x14;    // 0001 0100,T2R=1启动T2运行,T2x12=1,定时器2按1T计数
    32.     // 下面代码设置定串口2
    33.     S2CON = 0x15;                // 0001 0000 S2M0=0(最普遍的8位通信),REN=1(允许接收)
    34.     // 下面代码设置中断
    35.     IE2  =0x01;                      // 开串口2中断
    36.     EA   = 1;                      // 开总中断
    37. }
    38. void main()
    39. {
    40.     unsigned  char num=0;      
    41.     UART_init();
    42.     UART2_init();
    43.     while(1)
    44.     {               
    45.             UART_send_byte(num++);
    46.             delay500ms();
    47.     }
    48. }
    49. void UART2(void) interrupt 8  // 串行口2中断函数
    50. {
    51.     P00=!P00;
    52.     if(S2CON&0x02)           // 0x02=0000 0010,发送中断标志 S2TI=1
    53.     {
    54.             S2CON&=0xFD;   // 0xFD=1111 1101,清零发送中断标志 S2TI=0,               
    55.     }
    56.     if(S2CON&0x01)           // 0x01=0000 0001,接收中断标志 S2RI=1
    57.     {
    58.             S2CON&=0xFE;   // 0xFE=1111 1110,清零接收中断标志 S2RI=0,
    59.         P0 = S2BUF;               
    60.     }
    61. }
    复制代码








    222837lyn3uruqqppmunnq.jpg
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2023-5-11 07:17:38 | 显示全部楼层
    《51单片机轻松入门—基于STC15W4K系列》内容节选
    2.1.6  变量作用域
    作用域的定义是这样的,如果一个变量在某个文件或函数范围内是有效的,则称该文件或函数为该变量的作用域,在此作用域内可以使用该变量,所以又称变量在此作用域内“可见”,通常,变量的作用域都是通过它在程序中的位置隐式说明的。
    变量只能在定义它或说明它的范围内使用,而在该范围之外是不可见的,按作用域的大小可分为程序级、文件级、函数级及复合语句级(块级),其中程序级的作用域最大,属于程序级作用域的只有全局变量,在构成程序的所有文件中都是可见的,属于文件级的作用域的只有静态全局变量,属于函数级、复合语句级的变量称为局部变量,在下面的讨论中,我们会看到变量的作用域与变量的存储类型有关。
    局部变量 :
    ① 在一个函数内部定义的变量是局部变量,只能在函数内部使用(使用关键字auto,static,默认值auto可省略),在主函数内部定义的变量也是局部变量,其它函数也不能使用主函数中的变量。
    ② 局部变量在没有赋值以前的值是不确定的,是以前残留在内存里的随机值,所以在定义局部变量的时候一定要初始化。
    ③ 实际参数变量属于主调函数的局部变量。
    ④ 形式参数变量属于被调函数的局部变量,它的作用范围仅限于函数内部所用的语句块。
    ⑤ 在复合语句中定义的变量是局部于复合语句的变量,只能在复合语句块中使用。
    ⑥ 不同函数中可以使用同名变量,它们作用域不同,因此不会发生冲突。
    ⑦ 局部变量在函数被调用的过程中动态占有存储单元,调用结束立即释放。
    全局变量 :
    ① 在函数外部定义的变量是全局变量,其作用域是变量定义位置开始至整个程序文件结束,可使用前缀auto,static,默认值auto可省略,实际中全局变量一般是在程序的开头位置定义。
    ② 全局变量在没有赋值以前系统默认为0,全局变量初始化是在其定义时进行的,而其初始化仅执行一次,这种规则对于数组、结构体和联合体也同样适用。
    ③ 使用全局变量可增加函数间数据传递的渠道,全局变量可以将数据传入在作用域范围内的函数,也可以将数据传回到作用域范围内的其它函数,使用全局变量可让函数传回多个值,但一定要注意全局变量传递数据是数据传递的后门,全局变量在程序中任何地方都可以更新,使用全局变量会降低程序的安全性与移植性,因此,原则上尽量少用全局变量,能用局部变量的就不用全局变量,要避免局部变量全局化。
    ④ 使用其它文件的全局变量,可通过extern关键字引用,或用文件包含处理。
    ⑤ 局部变量若与全局变量同名,则在局部变量的作用域内,全局变量存在,但不可见,全局变量的作用被屏蔽。
    ⑥ 全局变量在程序运行过程中一直占用RAM存储单元。
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    无聊
    12 小时前
  • 签到天数: 139 天

    [LV.7]常住居民III

    17

    主题

    530

    回帖

    1237

    积分

    金牌会员

    积分
    1237
    发表于 2023-5-11 08:25:14 | 显示全部楼层
    好文!好书!!好人呀!!感谢分享!学习了!!
    不停地学习
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2023-5-29 22:06:28 | 显示全部楼层
    《51单片机轻松入门—基于STC15W4K系列》内容节选
    2.5 模块化编程
    2.5.1  头文件的编写

       执行菜单File→New新建一个空白文件,然后保存,保存路径选择当前工程所在文件夹,为方便阅读程序,文件名尽量与对应的*.c文件名相同,后缀名为*.h,模块化编程通常是一个*.c文件对应一个*.h文件,头文件编写中首先要使用条件编译命令防止头文件重包含错误,例如:
    #ifndef __STDIO_H__   //__ 是2个下划线
    #define __STDIO_H__   
    ……头文件代码块
    #endif
       一般格式是这样的:
        #ifndef <标识>
        #define <标识>
    ……头文件代码块
        #endif
        <标识>在理论上来说可以是自由命名的,为便于理解程序,实际使用一般是用头文件名并且全部大写,前后各加2个下划线,并把文件名中的“.”变成一个下划线。
    2.5.2  条件编译
    一般情况下,源程序中所有的行都参加编译,但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”,条件编译功能也可用条件语句来实现,但条件编译可以节省程序存储器空间,需要注意的是条件编译命令行结尾没有分号。
    第1种条件编译格式
        #ifdef 标识符
            语句段1;
    #else
            语句段2
    #endif
    功能说明:如果标识符已被#define命令定义过,则编译语句段1; 否则编译语句段2。
    示例: #define MASTER 1
               ┅┅
              #ifdef MASTER
                   SPCTL=0xf0;
              #else
                   SPCTL=0xe0;
              #endif
    第2种条件编译格式
         #ifndef  标识符
              语句段1;
    #else
              语句段2
    #endif
    功能说明:如果标识符未被#define命令定义过,则编译语句段1; 否则编译语句段2。
    第3种条件编译格式
    #if  常数表达式
    语句段1;
    #else
    语句段2;
    #endif
    功能说明:若#if指令后的常数表达式为真(随便什么数字,只要不是0),则编译语句段1,否则编译语句段2。
    例如:
    #define MAX 200
    #if MAX>999
    printf("compiled for bigger\n");
    #else
    printf("compiled for small\n");
    #endif
    2.5.3  多文件程序(模块化编程)
    我们第一章介绍的所有程序都很简单,只需要编写一个*.c文件,main()函数和普通函数都放在同一个*.c文件中,就是单文件程序,当程序量比较大时,我们应该对代码进行分类,不同类型的代码放到不同的*.c文件中,这就是多文件程序,也就是模块化编程的方式,采用模块化编程可以使整个工程脉络清晰,代码规划合理,有利于代码积累,重复利用,快速建立大型工程,在这里,我们把一个*.c或*.h文件就称为一个模块,模块化编程主要注意以下几点:
    ① 变量定义与初始化,函数体都放在 *.c文件中,类型定义、宏、端口定义、SFR声明、函数声明等都放在*.h文件中,若某个函数声明不放在.H文件中,则其它程序无法调用这个函数。
    ② 一个*.c文件配套一个*.h文件,由于*.c文件中用到的宏定义等可能都是在*.h文件中,所以*.c文件中要使用 #include "*.h"将自己对应的头文件包含进来,假设a.c文件需要调b.c文件中的函数,a.c除了包含自己对应的头文件外还需要包含b.c对应的头文件。
    ③ *.h中的所有内容都可以放在*.c中,但*.c中的变量定义初始化等不能放在*.h中。
    ④ 整个工程只能有一个main()函数。
    多文件程序能够实现的根本原理是C51将所有函数都认为是全局性的,而且是外部的, 可以被另一个文件中的任何一个函数调用,但是另一个文件调用该函数之前,则应在文件的开头(即所有函数外的最上端)声明被调函数,又因为声明的被调函数可能会很多,所以有了包含头文件的需要。
    接下来看一个流水灯程序采用模块化编程例子。
    例2.35  完整的多文件程序
    //*************** A模块包含下面2个文件 **********************
    // 文件a.h  声明定义
    #include "STC15W4K.H"
    #define PORT P0
    #define DelayTime 50000
    void fun1(void);
    void fun2(void);
    // 文件a.c        // 具体实现
    #include "b.h"     // 因为要用到"b.c"中delay(),所以必须有此命令
    #include "a.h"     // 因为要用到"a.h"中的符号PORT和DelayTime,所以必须有此命令
    void fun1(void)   // 流水灯(从左到右)
    {
        unsigned char i=0,temp=0x80;
        for(i=0;i<8;i++)
        {
            PORT=~temp;
            temp>>=1;
            delay(DelayTime);
        }
    }
    void fun2(void)   // 流水灯(从右到左)
    {
        unsigned chari=0,temp=0x01;
        for(i=0;i<8;i++)
        {
            PORT=~temp;
            temp<<=1;
            delay(DelayTime);
        }
    }
    //*************** B模块包含下面2个文件 **********************
    // 文件b.h   // 声明定义
    void delay(unsigned int time);
    // 文件b.c   //具体实现
    void delay(unsigned int time)
    {
        while(time--);
    }
    //*************** 主文件main.c **********************
    #include "a.h"    // 因为要用到"a.c"中fun1()、fun2(),所以必须有此命令
    #include "b.h"    // 因为要用到"b.c"中delay(),所以必须有此命令
    void main()
    {
        while(1)
        {
            fun1();
            delay(10000);
            fun2();
            delay(10000);
        }
    }

    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2023-6-8 07:24:36 | 显示全部楼层
    请问李先生,您的开发板为什么用两颗芯片,有什么特殊的吗?

    本实验板特点:

    1、完美的硬件仿真功能,可仿真STC单片机内部所有功能部件。
    2、电路板采用双核结构设计(2个STC15W4K58S4单片机),设计方式国内首创,相当于2个单片机开发板,可相互独立运行,也可联机运行。
    使用2个单片机目的:(A)是一种设计方法:当单片机系统软件和硬件都很复杂时使用2个或多个单片机可以大幅度降低硬件和软件的复杂程度,提高系统可靠性,这是作者多年的重要设计经验,作者曾在一个系统中使用过4个单片机同时运行 (B)使用2个单片机可以解决系统中2个高级中断谁也不能让谁的中断竞争问题。类似于一山不容二虎的问题彻底得到解决 (C)教材实验需要:2个单片机间高达8H2的高速硬件SPI通信必须使用2个单片机进行实验;计数器、频率计实验需要外部信号源,硬件电路可以实现,但电路复杂,调节不太方便,我们使用另一个单片机做信号源方便很多。(D)本板采用一个插件封装单片机与一个贴片封装单片机,既方便目前实验,又方便今后自己产品设计直接参照。
    3、外围功能模块多,最重要的是通过本实验板学到的是最新、最先进与最实用的知识,可直接用于实际产品研发。
    4、配套有老一点的书稿电子文档、辅助学习视频、纸质教材出版日期:2015.05.30。

    单片机干扰常见2种情况:(1)电源共地干扰,解决办法,单片机GND与大电流GND分开走线。
    (2)辐射干扰,STC12或15单片机本身抗干扰能力很强,一般由外中断干扰导致故障,可在外中断线加1K上拉电阻(强上拉),再并1uF电容到GND(干扰滤波)。
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2023-12-30 08:47
  • 签到天数: 2 天

    [LV.1]初来乍到

    2

    主题

    18

    回帖

    76

    积分

    注册会员

    积分
    76
    发表于 2023-10-19 22:01:00 | 显示全部楼层
    踏踏实实敲代码,编程就好!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    13 小时前
  • 签到天数: 156 天

    [LV.7]常住居民III

    110

    主题

    460

    回帖

    876

    积分

    高级会员

    积分
    876
    发表于 2024-4-15 13:39:54 | 显示全部楼层
    你好老师:我这里有两个问题,想问一下
    1、关于SSI通信的代码有视频讲解吗?
    2、接收数据的0-24的定义,前面JSDxx与后面的JSData^xx,后面序号怎么是乱的?还有31为啥???

    sbit JSD24=JSData^0;//接收最高位;0-24位共计25位;
    sbit JSD23=JSData^15;
    sbit JSD22=JSData^14;
    sbit JSD21=JSData^13;
    sbit JSD20=JSData^12;
    sbit JSD19=JSData^11;
    sbit JSD18=JSData^10;
    sbit JSD17=JSData^9;
    sbit JSD16=JSData^8;
    sbit JSD15=JSData^23;
    sbit JSD14=JSData^22;
    sbit JSD13=JSData^21;
    sbit JSD12=JSData^20;
    sbit JSD11=JSData^19;
    sbit JSD10=JSData^18;
    sbit JSD9=JSData^17;
    sbit JSD8=JSData^16;
    sbit JSD7=JSData^31;
    sbit JSD6=JSData^30;
    sbit JSD5=JSData^29;
    sbit JSD4=JSData^28;
    sbit JSD3=JSData^27;
    sbit JSD2=JSData^26;
    sbit JSD1=JSData^25;
    sbit JSD0=JSData^24;//接收最低位
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    19 小时前
  • 签到天数: 163 天

    [LV.7]常住居民III

    9

    主题

    837

    回帖

    3275

    积分

    论坛元老

    积分
    3275
     楼主| 发表于 2024-4-15 15:07:14 | 显示全部楼层
    序号是乱的是因为大小端模式。


    大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,存储模式类似把数据当作字符串顺序处理。

    小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,存储模式将地址的高低和数据位权有效地结合起来。


    大小端模式.jpg

    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-5 21:16 , Processed in 0.073393 second(s), 67 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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