查看: 9340|回复: 15
打印 上一主题 下一主题

【擂台挑战赛】马潮老师给出10道MCU实训题,欢迎各位挑战。

[复制链接]
跳转到指定楼层
沙发
发表于 2018-4-1 16:59:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1、MCU的使用不限制,任何所熟悉的8位或32位MCU,只要能实现题目功能都可以。本实训题指标性能制定考虑主要基于使用8位的51架构的MCU实现,使用32位MCU,比如STM32时,性能指标难度要相应提高调整。
注:原学习过以及熟悉使用51架构MCU的学员,请使用STC15F2K60S2(STC8A8K64S4A12)芯片,不建议使用标准架构MCS-51的“老”MCU芯片,如89C51、89C51等,因为本实训中的大部分题目用老的51芯片根本不能实现。
2、关于误差和精度的分析:MCU系统时钟的选择是设计中的一个方面,一旦确定,理论上则认为100%准确,不考虑误差。MCU内部硬件产生的误差也不作考虑。主要分析和思考的是从软件和系统设计不合理而产生的误差和不确定,以及如何避免和最大限度的减小。
3、首先要给出系统实现的设计方案报告,内容包括:选用的主要芯片、实现功能的方法描述与介绍,占用MCU的硬件资源,完成主要功能占用CPU的时间比例,性能分析(稳定可靠性,精度准度、误差等);主要电路草图,系统成本分析,完成时间估计。
4、根据设计方案动手实现:编程、调试。并在此基础上做进一步的思考:比如:设计方案是否有不足?考虑问题的思路是否正确?是否可以优化?是否还有更好的实现方法?
5、本套实训题共10题,包括基本练习6题,中级练习3题,高级练习1题。根据学员完成情况,决定培训内容和进程,同时也是学员能力评定的重要指标之一。真正有能力和实力的学员应该认真和尽快去完成。
6、实现硬件平台基于因仑的MCU实验箱(板)的硬件平台上完成,第10题需要适当增加硬件。因仑的MCU实验箱(板)上提供有STC8F4K60S4、AVR、430、PIC、STM32等常用8位(32位)的MCU核心板,可选择熟悉的MCU来完成。同时MCU实验箱(板)主板也提供了充足的外设。
       本实训题有提供比较和参考实例,其均在因仑的MCU实验箱(板)的硬件平台上,使用STC最新8位51架构的STC8A8K64S4A12实现完成。
回复

使用道具 举报

推荐
发表于 2018-4-4 09:22:56 | 只看该作者
本帖最后由 LiMeng 于 2018-4-4 09:30 编辑
liliuyang 发表于 2018-4-1 17:03
【NO.1】  使用MCU产生6个方波输出和2个单脉冲输出

题目来源:大学电子基础实验用数字逻辑实验箱改造―― ...

我做出来了,方案如下:用了STC公司最新的STC8单片机,STC8单片机共有5个定时器,分别产生前五个方波,100Hz的定时器进中断进行分频产生最后一个方波,并为按键检测提供状脉冲。
单片机的定时器统一采用自动重载模式,并在溢出后直接翻转I/O口,整个过程除了最后10Hz进中断,其他均为硬件产生,故精度是以单片机的晶振精度为基准的。程序如下:
/***********************************************************************
* 文 件 名: 方波发生器
* 使用芯片: STC8A8K64S4A12
* 使用晶振: 24.0000MHz
* 硬件连接: P0.0连接按键
* 描述功能: P5.4输出3MHz,P3.5输出1MHz,P3.4输出100KHz,P1.3输出10KHz,P0.5输出1KHz,P0.7输出100Hz,P04输出10Hz,P0.1、P0.2为单脉冲
* 日    期: 2018/03/20
* 作    者: 李猛
* 版    本: V1.0
* 修改记录: 无
******************头文件***********************************************/
#include <STC8.H>
#include <intrins.h>

/*****************宏定义***********************************************/
#define CLKO                24000000                        //系统时钟频率
#define u8                        unsigned char
#define u16                unsigned int
#define u32                unsigned long

//=========定时器计算公式==================
#define Time_1T_ms        CLKO/1000                        //定时器1T模式下毫秒级延时计算公式
#define Time_12T_ms        CLKO/12/1000                //定时器12T模式下毫秒级延时计算公式
#define Time_1T_us        CLKO/1000000                //定时器1T模式下微秒级延时计算公式
#define Time_12T_us        CLKO/12/1000000        //定时器12T模式下微秒级延时计算公式

/*****************定义全局变量******************************************/
bit KEY_ON ,FangBo;                //定义标志位

/*************************************************************************
* 函 数 名: Cksel_Init
* 功    能: 初始化系统时钟
* 入口参数: 无
* 出口参数: 无
* 备    注: 无
*************************************************************************/
void Cksel_Init(void)
{
        P_SW2          = 0x80;                //特殊功能寄存器位于扩展RAM区域,访问需先将P_SW2的BIT7设置为1
        IRC24MCR = 0x80;                //使用内部24MHz晶振
        while(!(IRC24MCR & 1));        //等待时钟稳定
        CLKDIV          = 0x00;                //主时钟不分频
        CKSEL          = 0x70;                //选择外部输入时钟信号并在P5.4输出系统时钟的八分频
        P_SW2          = 0X00;
}

/*********************************************************************
* 函 数 名: IO_Init初始化函数
* 功    能: 初始化I/O口
* 入口参数: 无
* 出口参数: 无
* 备    注:
*            PxM1   PxM0
*             0      0     准双向I/O
*             0      1     推挽输出      
*             1      0     高阻输入     
*             1      1     开漏输出  
***********************************************************************/
void IO_Init(void)
{
        P0M1 = 0x00;    P0M0 = 0x00;//    P0 = 0x00;     //P0口设置成准双向I/O  同时全部置低
        P1M1 = 0x00;    P1M0 = 0x00;//    P1 = 0x00;     //P1口设置成准双向I/O  同时全部置低
        P2M1 = 0x00;    P2M0 = 0x00;//    P2 = 0x00;     //P2口设置成准双向I/O  同时全部置低
        P3M1 = 0x00;    P3M0 = 0x00;//    P3 = 0x00;     //P3口设置成准双向I/O  同时全部置低
        P4M1 = 0x00;    P4M0 = 0x00;//    P4 = 0x00;     //P4口设置成准双向I/O  同时全部置低
        P5M1 = 0x00;    P5M0 = 0x00;//    P5 = 0x00;     //P5口设置成准双向I/O  同时全部置低
        P6M1 = 0x00;    P6M0 = 0x00;//    P6 = 0x00;     //P6口设置成准双向I/O  同时全部置低
        P7M1 = 0x00;    P7M0 = 0x00;//    P7 = 0x00;     //P7口设置成准双向I/O  同时全部置低
}

/*********************************************************************
* 函 数 名: Routine_Init
* 功    能: 初始化中断
* 入口参数: 无
* 出口参数: 无
* 备    注: 在主函数初始化的最后开启总中断(EA = 1;)
*          IP、IP2  IPH、IP2H    中断优先级控制寄存器
*             0               0        最低级(0级)
*             0               1        较低级(1级)      
*             1              0        较高级(2级)     
*             1                    1        最高级(3级)  
***********************************************************************/
void Routine_Init(void)
{        
//===============T0============================1MHz 0.5us P3.5
        TL0          = 65536-5*Time_1T_us/10;                //对定时器0赋初值        1T
        TH0          = 65536-5*Time_1T_us/10 >> 8;
        TMOD         &= 0;                                //0000 0000               
        AUXR         |= T0x12;                        //1000 0000
        INTCLKO |= T0CLKO;                        //0000 0001        溢出自动取反
        TF0          = 0;                                //T0溢出标志位清零
        TR0          = 1;                                //T0运行控制位
//        ET0          = 1;                                //定时/计数器T0中断允许位

//===============T1============================100KHz 5us P3.4
        TL1          = 65536-5*Time_1T_us;                //对定时器1赋初值        1T
        TH1          = 65536-5*Time_1T_us >> 8;
        TMOD         &= 0;                                //0000 1000
        AUXR         |= T1x12;                        //0100 0000
        INTCLKO |= T1CLKO;                        //0000 0010        溢出自动取反
        TF1          = 0;                                //T1溢出标志位清零
        TR1          = 1;                                //T1运行控制位
//        ET1          = 1;                              //定时/计数器T1中断允许位
        
//===============T2============================10KHz 50us P1.3
        TL2                 = 65536-50*Time_1T_us;                //对定时器2赋初值        1T
        TH2          = 65536-50*Time_1T_us >> 8;
        AUXR         |= 0x14;                        //0001 0100
        INTCLKO |= T2CLKO;                        //0000 0010        溢出自动取反
//        IE2         |= ET2;                                //定时/计数器T2中断允许位
        
//===============T3============================1KHz 500us  P0.5
        TL3          = 65536-50*Time_1T_us*10;                //对定时器3赋初值        1T
        TH3          = 65536-50*Time_1T_us*10 >> 8;
        T4T3M         |= 0x0B;                        //0000 1011
//        IE2         |= ET3;                                //定时/计数器T3中断允许位
        
//===============T4============================100Hz 5ms        P0.7
        TL4          = 65536-5*Time_12T_ms;                //对定时器3赋初值        12T
        TH4          = 65536-5*Time_12T_ms >> 8;
//        T4T3M         &= 0x0F;                        //0000 1111
        T4T3M         |= 0x90;                        //1001 0000
        IE2         |= ET4;                                //定时/计数器T4中断允许位
}

/*************************************************************************
* 函 数 名: Read_Key
* 功    能: 监测按键子程序
* 入口参数: 无
* 出口参数: Key_return
* 备    注: 无
*************************************************************************/
#define Key_input        P00                //按键输入端口
#define Key_state_0        0                //检测按键状态
#define Key_state_1        1                //确认按键状态
#define Key_state_2        2                //待释放按键状态
u8 Read_Key(void)
{
        static u8 Key_state = 0;                //静态局部变量,仅执行一次
        static u8 Key_return = 0;
        switch(Key_state)
        {
                case Key_state_0:        //检测阶段
                        if(!Key_input)                                        //如果有按键按下
                                Key_state = Key_state_1;        //转入确认阶段
                        break;
                case Key_state_1:        //确认阶段
                        if(!Key_input)                                        //若还有按键按下
                        {
                                Key_state = Key_state_2;        //转入释放阶段
                                Key_return = 1;                                //返回值置“1”
                        }
                        else
                        {
                                Key_state = Key_state_0;        //如果没有按键按下,则认为是抖动,返回检测阶段
                                Key_return = 0;                                //返回值置“1”
                        }
                        break;
                case Key_state_2:        //待释放阶段
                        if(!Key_input)                                        //等待按键释放
                                Key_state = Key_state_2;        //转入检测阶段
                        else
                        {
                                Key_return = 0;
                                Key_state = Key_state_0;        //转入检测阶段
                        }
                        break;
        }
        return Key_return;                                                //返回状态
}

/*************************************************************************
* 函 数 名: main主函数
* 功    能: 执行主程序
* 入口参数: 无
* 出口参数: 无
* 备    注: 无
*************************************************************************/
void main(void)
{        
        Cksel_Init();                //初始化系统时钟
        IO_Init();                        //I/O口初始化
        Routine_Init();     //中断初始化函数
        EA = 1;                                //总中断允许位
        while(1)            //死循环
        {
                if(KEY_ON)                                        //10ms时间到
                {
                        KEY_ON = 0;                        //清除标志位
                        switch(Read_Key())
                        {
                                case 0:        //检测阶段
                                        P01 = 1;
                                        P02 = 0;
                                        break;
                                case 1:        //确认阶段
                                        P01 = 0;
                                        P02 = 1;
                                        break;
                        }        
                }
        };
}

/*************************************************************************
* 函 数 名: TM4_Rountine
* 功    能: 定时器4中断服务程序
* 入口参数: 无
* 出口参数: 无
* 备    注: 无
**************************************************************************/
void TM4_Rountine(void)        interrupt 20
{
        u8 j,i;                                        //定义变量
        
        AUXINTIF &= ~T4IF;                //清中断标志位
        
        if(++j >= 2)                        //两分频
        {
                j = 0;
                KEY_ON = 1;                        //置按键标志位
                if(++i >= 5)                //五分频
                {
                        i = 0;
                        P04 = !P04;                //10Hz P1.0
                }
        }
}

回复 支持 2 反对 0

使用道具 举报

板凳
 楼主| 发表于 2018-4-1 17:03:29 | 只看该作者
【NO.1】  使用MCU产生6个方波输出和2个单脉冲输出

题目来源:大学电子基础实验用数字逻辑实验箱改造――由箱改造成板,目的是学生可以带回到寝室作实验。原数字逻辑实验箱上的多路方波信号源使用了多片逻辑电路芯片实现,现要求使用一片20PIN以下的MCU替代。
1、6路方波输出源,方波的频率为1M、100K、10K、1K、100Hz、10Hz
2、2路单脉冲源。外接一个按键,按下按键后,一个I/O口输出低电平(另一个输出高电平),释放按键后该I/O口恢复高电平(另一个恢复为低电平),要作按键消抖处理。
3、给出系统实现的设计方案,方案中必须给出各个输出方波信号的精度估计,以及可能产生的设计误差估算和产生原因。
4、具体动手实现
5、实现后,分析完成6路方波产生功能所占用CPU的百分比。
6、 本设计方案先在实验板上采用已有的MCU实现,再整理成工程上实用的设计方案,此时只是完成上面所描述的功能,考虑到性价比、PCB占用的面积等,应该选择20PIN以下的MCU芯片。


回复 支持 反对

使用道具 举报

地板
 楼主| 发表于 2018-4-1 17:05:53 | 只看该作者
【NO.2】  产生简单音频提示音乐,在蜂鸣器上发出

在许多简单应用中,需要利用单片机系统产生各种音乐用于报警和提示等,如早期手机的来电铃声,儿童玩具,时钟的音乐报时等。用单片机产生简单音频发声的原理很简单,就是由I/O引脚输出不同频率的脉冲信号,再将信号放大,推动发声器件发声(这里是指在要求不高的情况下,用不同频率的脉冲方波替代正弦波)。

1、音乐样本(儿童歌曲“爱北京天安门”的第一句):
5   i  5   4 | 3   2  1 | 1 1  2  3 | 3 1  3  4 | 5 -
2、8音阶C调频率(周期)对应表

表8-2 8位音符的频率(周期)对应表
音符
1
2
3
4
5
6
7
i(高音)
数字表示
1
2
3
4
5
6
7
8
频率(个)
523
578
659
698
784
880
988
1046
周期us
1912
1730.1
1517.5
1432.7
1275.5
1136.4
1012.1
956
1/4节拍
52.3
57.8
65.9
69.8
78.4
88
98.8
104.6
*半周期us
956
865
759
716
638
568
506
470
*1/4节拍
105
116
132
140
157
176
198
209
3、给出系统实现的设计方案,要求使用MCU内部最少的硬件资源,和占用CPU时间最少,容易移植或拼入其它系统中使用。(提示,参考《AVR单片机嵌入式系统原理与应用实践(第2版)》一书)
4、具体动手实现
5、扩展思考:
   1/使用什么样的蜂鸣器?底层驱动如何编写

   2/嵌入式系统不是通用计算机系统

回复 支持 反对

使用道具 举报

4#
 楼主| 发表于 2018-4-1 17:10:16 | 只看该作者
【NO.3】 使用16*16点阵设计一个电梯运行指示器
1、4个控制按键,功能为上行、下行、停止、广告4个状态
2、电梯运行停止:显示静止的水平线,中间位置,(16*16点阵 参考图1)
3、上行状态时:显示向上移动的箭头(参考图2)。移动过程中,2个箭头之间空4行(参考图3)
4、下行状态时:显示向下移动的箭头,移动过程中,2个箭头之间空4行
5、广告状态时:水平横向移动显示“上海因仑”4个汉字。




6、基本要求,显示正确,亮度均匀,无拖尾、不闪烁,移动速度均匀,按键扫描和消抖与显示扫描无冲突。
7、系统设计报告中需要给出外围电路,尤其是具体说明16*16点阵的硬件电路,以及如何驱动和扫描显示的,说明具体的扫描时间计算,以及如何保证以上功能的正确实现。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?加入因仑

x
回复 支持 反对

使用道具 举报

5#
 楼主| 发表于 2018-4-1 17:11:36 | 只看该作者
【NO.4】  将NO.2和NO.3合并成一个系统

将设计题二和设计题三合并为一个系统,检验上面2个设计方案是否非常容易组合使用。
1、  当进入电梯上行和下行状态,箭头移动的同时,播放一遍音乐1(代替电梯运行提示音)。
2、  当电梯处在广告显示状态时,循环播放音乐2(代替广告声音)。

回复 支持 反对

使用道具 举报

6#
 楼主| 发表于 2018-4-1 17:14:49 | 只看该作者
【NO.5】   一线串口底层驱动代码设计

某OTP语音芯片支持一线串口控制模式。该模式可以利用MCU使用一个I/O口线给语音芯片发送命令以达到控制语音芯片的目的,实现控制语音选择播放、停止、循环等。
命令长度为1个字节,采用十六进值数据,命令定义如下:


  
命令字(十六进制)
  
功能
0x00
播放第0段语音
0x01
播放第1段语音
。。。。
。。。。
0xce
播放第206段语音
0xcf
播放第207段语音
0xe0 – 0xef
音量调节 16级
0xf0
关闭功放
0xf1
打开功放
0xf2
循环播放当前语音
0xfe
停止播放当前语音
控制时序如下:先置数据线高电平8ms 的旪间,再将数据信号拉低5ms,最后发送数据。数据以电平占空比的形式计算,高电平与低电平数据占空比1:3 即代表数据位0,高电平与低电平数据位占空比为3:1代表数据位1。高电平在前,低电平在后。数据信号先发低位再发高位。在发送数据时,D0~D7表示一个地址或者命令数据,数据中的00H~DBH为地址指令,E0H~EFH为音量调节命令,F2H为循环播放命令,FEH为停止播放命令。详细时序如下图:




器件手册提供了一段低层驱动代码:
Void send_com(byte addr)
{
Sda = 1;
wait(200);                 /* 8ms 以上 */
sda=0;
wait(300);                 /* 5ms */
for(i=0;i<8;i++)
{
             sda=1;
             if(addr & 1)
             {
                  wait(15);         /* 600us */
                  sda=0;
                  wait(5);          /* 200us */
             }
             else
             {
                  wait(5);                /* 200us */
                  sda=0;
                  wait(15);               /* 600us */
             }
             addr>>=1;
}
sda=1;
}
该函数发送一个字节命令,大约需要20ms(8+5+0.8*8)。
请使用一个定时器配合一个中断来控制I/O输出,编写一个能控制该芯片工作的低层函数,要求占用CPU时间最少。(CPU和T/C并行工作处理练习)
本题只要设计报告和底层原代码,不需要具体实现。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?加入因仑

x
回复 支持 反对

使用道具 举报

7#
 楼主| 发表于 2018-4-1 17:16:07 | 只看该作者
【NO.6】    利用PWM功能产生1KHz的正弦波

尽量利用MCU资源产生频率最接近、平滑度最好的正弦波,给出输出正弦波的平滑度估计、频率误差估计。
深入讨论:
有哪些方法可以改变输出正弦波的频率?这些改变的方法对波形平滑度有影响吗?实现的可行性如何。
要进一步提高输出正弦波的平滑度有什么方法可以实现,有什么限制?
回复 支持 反对

使用道具 举报

8#
 楼主| 发表于 2018-4-1 17:17:00 | 只看该作者
【NO.7】 设计一个简易的高精度频率计

1、使用8个LED数码管显示频率测试结果
2、实现频率测量量程的自动转换
3、首先给出设计方案报告,说明频率计测试频率所采用的方法、能够测试频率的范围,不同量程测试结果的精度和误差、以及测量显示频度(每秒几次)
4、因仑的MCU实验箱(板)的硬件平台上有方波发生器,产生1HZ~16M之间16个不同频率的方波,可作为测试频率源验证设计
回复 支持 反对

使用道具 举报

9#
 楼主| 发表于 2018-4-1 17:18:08 | 只看该作者
【NO.8】  带语音报时的实时时钟

1, 使用6位LED数码管显示时分秒
2, 三个按键,2个用于时间设定,一个用于语音报时(按下播报“当前时间是xx时xx分xx秒”)
3, 参考《AVR单片机嵌入式系统原理与应用实践(第2版)》一书第11.3节和第19章内容

回复 支持 反对

使用道具 举报

10#
 楼主| 发表于 2018-4-1 17:19:06 | 只看该作者
【NO.9】  汽车路码表
设计一轿车路码表,功能要求:
一、使用8位LED数码管作为显示,左边4位显示总里程数(KM),总里程数带记忆(掉电记忆功能)
二、右边4位数码管显示速度(KM/H),小数点一位,为每秒平均时速
三、设计车轮转动圈数的传感器信号和输出电路,磁、光都可以(本实训题不使用测速电机传感器),该传感器电路能配合MCU系统测量车辆的速度、车辆停顿、和转动方向,注意说明如何消除车辆抖动造成的误差和影响。
四、车辆倒车时,蜂鸣器提示 每秒1次(慢速)
五、车辆前进,当速度超过120KM/H时,蜂鸣器快速提示(每秒3次)
设计方案含具体的硬件电路、软件实现设计
设计提示:
1/ 轿车车轮直径0.615m,每转一圈0.615*3.14=1.93米
2/ 设定车轮最高转速(极限值)为35圈/秒,则最高时速为
1.93m * 35/s *3600s = 243180米  (243.2千米/小时)
3/ 按上面极限值计算,每毫秒最快转动角度(距离)为:
(360 * 35)/ 1000 = 12.6度
(1.93 * 35) / 1000 = 0.068米    (68毫米)
4/ 调试过程中可使用因仑的MCU实验箱(板)的硬件平台上方波发生器产生的1Hz-500Hz的方波模拟不同速度时的车轮转动产生脉冲的输入信号。
例如:车轮转一圈产生一个脉冲信号,那么31.25Hz的方波模拟的速度为:
    1.93m * 31.25/s * 3600s =217125米 (217.125千米/小时)
而1.953125Hz的方波模拟的速度为:
1.93m * 1.953125/s * 3600s = 13570.3125米 (13.570千米/小时)
正式验证可采用一台低频信号发生器,调节产生0-500Hz方波信号来模拟车轮转动产生的输入信号。
回复 支持 反对

使用道具 举报

11#
 楼主| 发表于 2018-4-1 17:19:58 | 只看该作者
【NO.10】  WAVE播放器

FAT文件系统下载及例程参考http://elm-chan.org/fsw/ff/00index_p.html
参考《AVR单片机嵌入式系统原理与应用实践(第2版)》一书第19章

回复 支持 反对

使用道具 举报

13#
发表于 2018-4-4 09:48:37 | 只看该作者
我也是小白一枚,程序有问题的地方还望大家多多指教
回复 支持 反对

使用道具 举报

14#
发表于 2018-4-13 18:21:37 | 只看该作者
本帖最后由 LiMeng 于 2018-4-15 11:09 编辑
liliuyang 发表于 2018-4-1 17:03
【NO.1】  使用MCU产生6个方波输出和2个单脉冲输出

题目来源:大学电子基础实验用数字逻辑实验箱改造―― ...

方波发生器开发计划说明书
为了更好的锻炼和提升大家的单片机实战开发能力,华东师范大学马潮教授根据多年教学和项目开发经验亲自为单片机爱好者出了十道由易到难的MCU开发题目。本项目为十道题目中的第一题。
1.1项目概述
题目来源:大学电子基础实验用数字逻辑实验箱改造――由箱改造成板,目的是学生可以带回到寝室作实验。原数字逻辑实验箱上的多路方波信号源使用了多片逻辑电路芯片实现,现要求使用一片20PIN以下的MCU替代。
1.2项目内容
1、6路方波输出源,方波的频率为1M、100K、10K、1K、100Hz、10Hz
2、2路单脉冲源。外接一个按键,按下按键后,一个I/O口输出低电平(另一个输出高电平),释放按键后该I/O口恢复高电平(另一个恢复为低电平),要作按键消抖处理。
3、给出系统实现的设计方案,方案中必须给出各个输出方波信号的精度估计,以及可能产生的设计误差估算和产生原因。
4、具体动手实现
5、实现后,分析完成6路方波产生功能所占用CPU的百分比。
6、 本设计方案先在实验板上采用已有的MCU实现,再整理成工程上实用的设计方案,此时只是完成上面所描述的功能,考虑到性价比、PCB占用的面积等,应该选择20PIN以下的MCU芯片。
1.3项目方案
产生脉冲方波需使用MCU内部硬件定时器资源,故MCU需满足自带定时器功能,且不应少于三个。
产品输出6路方波和两路脉冲和一个按键,共占用9个I/O口,加上MCU必须的电源2个,下载程序端口2个,为保证方波的精度,使用外部晶振,故外部晶振占用I/O 2个,共需引脚9+2+2+2=15个。
使用芯片:STC15F2K60S2        20脚
使用晶振:6.000MHz (备用12.000MHz、24.000MHz)
STC15F2K60S2芯片内部拥有3个定时器,且含有自动重载与自动I/O翻转功能。可满足高频的产生,且启动后不占用CPU。
频率        1MHz        100KHz        10KHz        1KHz        100Hz        10Hz
周期时间        1us        10us        100us        1ms        10ms        100ms
翻转时间        0.5us        5us        50us        500us        5ms        50ms
1MHz、100KHz和10KHz采用定时器硬件翻转I/O实现,保证其正常工作后不占用CPU资源。控制产生10KHz的定时器溢出后进中断,完成1KHz、100Hz、10Hz的产生。
考虑到PCB的布局方便参照单片机引脚顺序(具体见下载器中的引脚定义),引脚定位
频率        1MHz        100KHz        10KHz        1KHz        100Hz        10Hz
引脚        P3.5         P3.4                 P3.0                 P3.6   P3.7        P3.3
按键连接P1.4,要翻转的I/O口为P1.0、P1.1

因采用的是新型51单片机,故程序执行效率有提高,但还达不到1T,根据数据手册提供的执行效率0.7计算,6*0.7*50 = 210条指令。在中断函数中执行代码最多为15条指令,假设其指令均为慢指令(3个时钟执行一条)15*3=45占比为45/210=21.43%,且程序也并非每次进去都执行全部的程序,故CPU有充足的时间执行完指令。
        采用6.000MHz晶振可满足题目要求,虽降低了单片机的执行速度,但增加了系统稳定性,也降低了单片机功耗。
1.4题目回答:
3、由于1MHz与100KHz10KHz均有定时器自动重载和自动翻转I/O产生,故这三个频率的精度取决于外部晶振的精度,只要外部晶振保证精度足够,这三个频率则相当准确。
        1KHz、100Hz、10Hz这三个均来自10KHz的分频,由于要进中断执行程序,故会有相应的误差,准度由程序决定,根据计算准度可以保证达到,精度误差最多在10条指令的执行时间以内,依旧采取最大误差计算方法:10*3*1/6=5us,1KHz时间500us,精度99%;1KHz时间5000us,精度99.9%;10Hz时间50000us,精度99.99%。
5、21.43%(具体参见项目方案)

针对中断函数更加好的改进
采用“--”“==”的方式写出的程序经编译,得到汇编15条指令,占用CPU21.43%
采用“++”“==”的方式写出的程序经编译,得到汇编20条指令,占用CPU28.57%
采用“++”“>=”的方式写出的程序经编译,得到汇编25条指令,占用CPU35.71%
(具体参见程序),故一个好的程序,经过程序的优化,对CPU效率的提升是有很大效果的。
回复 支持 反对

使用道具 举报

15#
发表于 2018-7-28 07:51:07 | 只看该作者
LiMeng 发表于 2018-4-4 09:22
我做出来了,方案如下:用了STC公司最新的STC8单片机,STC8单片机共有5个定时器,分别产生前五个方波,100 ...

有个疑问,该程序中,主函数while(1)对应的{}后面为什么有个;
回复 支持 反对

使用道具 举报

16#
发表于 2018-7-28 10:54:27 | 只看该作者
ying.x 发表于 2018-7-28 07:51
有个疑问,该程序中,主函数while(1)对应的{}后面为什么有个;

属于一条语句,C语言中语句的结束就是以";"结束的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

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