[单片机类] 【灯光控制任务书】+看中了那个行车记录仪(视频已上传)

[复制链接]
1091|37
 楼主 | 2018-3-12 14:52 | 显示全部楼层 |阅读模式
本帖最后由 caijie001 于 2018-3-13 18:40 编辑

CT107D单片机综合训练平台
主控      STC89C52RC(IAP15F2K61S2那个转接板找不到了就用89C52代替了)
J4         UART
J15       51
J13       MM
J5         BTN
晶振     11.0592M(因为用到了波特率)

视频演示

http://v.youku.com/v_show/id_XMzQ1Nzk2NzI5Mg==.html?spm=a2h3j.8428770.3416059.1
 楼主 | 2018-3-12 15:40 | 显示全部楼层
本帖最后由 liupk 于 2018-4-3 09:28 编辑

这个是程序

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
| 2018-3-12 16:41 | 显示全部楼层
perfect....完美!
 楼主 | 2018-3-12 17:08 | 显示全部楼层

| 2018-3-12 17:14 | 显示全部楼层

l老司机了吧...
有空再看看你的源码....
 楼主 | 2018-3-13 09:20 | 显示全部楼层
ohy3686 发表于 2018-3-12 17:14
l老司机了吧...
有空再看看你的源码....

咦。。。小鲜肉,小鲜肉
| 2018-3-13 10:11 | 显示全部楼层
题目好直接,就是要行车记录仪~
 楼主 | 2018-3-13 10:37 | 显示全部楼层
小鱼儿1045 发表于 2018-3-13 10:11
题目好直接,就是要行车记录仪~

工具箱我也不介意
| 2018-3-13 13:13 | 显示全部楼层
这么巧,我也看上了行车记录仪哈哈哈

评论

一路向北lm 2018-3-27 08:08 回复TA
看来要被抢了 
 楼主 | 2018-3-13 13:47 | 显示全部楼层
21ic小喇叭 发表于 2018-3-13 13:13
这么巧,我也看上了行车记录仪哈哈哈

英雄所见略同
| 2018-3-13 16:08 | 显示全部楼层

把我心里话给说出来了
| 2018-3-13 18:44 | 显示全部楼层
不错不错啊,很强
| 2018-3-13 18:45 | 显示全部楼层
如果是讨论分享的话,可以说明下思路,给那些参加的同学一些思路感谢,顶你上去
| 2018-3-14 12:26 | 显示全部楼层
楼主应该多分享点
 楼主 | 2018-3-14 13:32 | 显示全部楼层
本帖最后由 liupk 于 2018-3-14 13:36 编辑

1.下面简单的介绍一下本次程序部分,好多我自己理解的也不到位。大家见谅,仅供参考。
主控      STC89C52RC(IAP15F2K61S2那个转接板找不到了就用89C52代替了)
J4         UART
J15       51
J13       MM
J5         BTN
晶振     11.0592M

 楼主 | 2018-3-14 13:35 | 显示全部楼层
2.因为用的是MM模式,结合该平台的硬件的特点可以使用  XBYTE  操作
主要是MM可以简化程序,尤其是数码管显示方面,简化了不少程序。(已经上传MM编程介绍,和官方例程)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主 | 2018-3-14 14:00 | 显示全部楼层
本帖最后由 liupk 于 2018-3-14 14:35 编辑

3.这个是主程序

        cls_display();关闭数码管显示
        cls_buzz();关闭蜂鸣器
        cls_led();关闭LED
        cls_relay();关闭继电器


根据题目要求需要实现从L1~L8依次逐个点亮,再依次逐个熄灭;然后检查数码管,从左到右依次点亮数码管的所有段码,再依次从左到右熄灭。
        test_led_on();从左到右依次点亮LED
        test_led_off();从右到左依次关闭LED
        test_display_on();从左到右依次点亮数码管
        test_display_off();从左到右依次关闭数码管
下面配置定时器0作为时钟,配置为每隔1ms进入一次中断:(进入中断做下面三个事情)     ConfigTimer0(1);
(1)每隔1ms进入一次中断。ms+1,当ms为1000时候代表一秒钟时间
(2)每隔1ms进入一次中断。display(); 执行一次,也就是数码管动态刷新时间为1ms
(3)每隔1ms进入一次中断。intr+1,当intr为10的时候代表10ms时间此时把按键的标志位置一key_flag = 1;  表示每隔10ms按键扫描一次
下面配置波特率,根据要求把波特率配置为9600;(11.0592M计算波特率更加准确。)        ConfigUART(9600);


void InterruptUART() interrupt 4
{
    if (RI)  //接收到字节
    {
        RI = 0;  //手动清零接收中断标志位
        RxdByte = SBUF;  //接收到的数据保存到接收字节变量中
               
                if(uart_flag)//这个条件是为了题目中   (5) 读取运行时间命令中,低4位保留,各位为0,返回3个字节的时间数据,用16进制的BCD码表示,排列顺序分别为:
                                                                       如果系统运行的时间为12时24分16秒则收到读取时间命令字后,然会3个字节,分别是:0x12 0x24 0x16    如果收到了
                                                                             0XB0    则返回当前时间到串口
                {
                        uart_flag = 0;
                        uart_sendstring(str);
                }
    }
    if (TI)  //字节发送完毕
    {
        TI = 0;  //手动清零发送中断标志位
    }
}


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主 | 2018-3-14 14:12 | 显示全部楼层
本帖最后由 liupk 于 2018-3-14 14:36 编辑

下面对主函数中的每个程序做单独的介绍
        cls_display();
        cls_buzz();
        cls_led();
        cls_relay();

               |
               |
               |
               |

               |
               |

               |
               |

都是利用XBYTE操作

XBYTE[0xA000] = 0x00;关闭蜂鸣器
XBYTE[0x8000] = 0xFF;关闭LED

这个是数码管的
XBYTE[0xC000] = 0xFF; //位选打开
XBYTE[0xE000] = 0xFF; //段码
XBYTE[0xC000] = 0x00;; //位选关闭


/*
*********************************************************************************************************
*        函 数 名: cls_buzz
*        功能说明: 上电关闭蜂鸣器
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void cls_buzz(void)
{
        XBYTE[0xA000] = 0x00;
}

/*
*********************************************************************************************************
*        函 数 名: cls_relay
*        功能说明: 上电关闭继电器
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void cls_relay(void)
{
        XBYTE[0xA000] = 0x00;
        
}

/*
*********************************************************************************************************
*        函 数 名: cls_led
*        功能说明: 上电关闭LED
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void cls_led(void)
{
        XBYTE[0x8000] = 0xFF;
        
}

/*
*********************************************************************************************************
*        函 数 名: cls_display
*        功能说明: 上电关闭数码管(共阳)
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void cls_display(void)
{
        XBYTE[0xC000] = 0xFF; //位选打开
    XBYTE[0xE000] = 0xFF; //段码
        XBYTE[0xC000] = 0x00;; //位选关闭
        
}








 楼主 | 2018-3-14 14:24 | 显示全部楼层
本帖最后由 liupk 于 2018-3-14 14:37 编辑

        test_led_on();
        test_led_off();
        test_display_on();
        test_display_off();

               |
               |
               |
               |

               |
               |

               |
               |
先说    test_led_on();

/*
*********************************************************************************************************
*        函 数 名: test_led_on
*        功能说明: 测试LED依次点亮
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void test_led_on(void)
{
        unsigned char i = 0;
        for(i = 0;i<=8;i++)
        {
                 XBYTE[0x8000] = (0xFF<<i);
                Delay100ms();        
        }
        
}


大约每隔100ms移动一次


然后是   test_led_off();

/*
*********************************************************************************************************
*        函 数 名: test_led_off
*        功能说明: 测试LED依次熄灭
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void test_led_off(void)
{
        unsigned char i = 0;
        for(i = 0;i<=8;i++)
        {
                 XBYTE[0x8000] = ~(0x7F>>i);
                Delay100ms();        
        }
        
}

从右到左依次灭

然后是    test_display_on();

/*
*********************************************************************************************************
*        函 数 名: test_display_on
*        功能说明: 测试数码管(共阳依次点亮)
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void test_display_on(void)
{
        unsigned char i = 0;
        XBYTE[0xE000] = 0x00; //段码
        for(i = 0;i<=8;i++)
        {
                 XBYTE[0xC000] = ~(0xFE<<i); //位选           
                Delay100ms();        
        }
}



从左到右依次亮

然后是   test_display_off();

/*
*********************************************************************************************************
*        函 数 名: test_display_off
*        功能说明: 测试数码管(共阳依次熄灭)
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void test_display_off(void)
{
        unsigned char i = 0;
        XBYTE[0xE000] = 0x00; //段码
        for(i = 0;i<=8;i++)
        {
                 XBYTE[0xC000] = (0xFE<<i); //位选           
                Delay100ms();        
        }
}

从左到右依次灭
 楼主 | 2018-3-14 14:33 | 显示全部楼层
本帖最后由 liupk 于 2018-3-14 15:03 编辑

        ConfigTimer0(1);
        ConfigUART(9600);

               |
               |
               |
               |

               |
               |

               |
               |
为了移植方便,以前我就把这些配置参数封装好了,方便随时摘抄

先说第一个     ConfigTimer0(1);

/*
*********************************************************************************************************
*        函 数 名: ConfigTimer0
*        功能说明: 配置并启动T0,ms-T0定时时间
*        形    参:ms
*        返 回 值: 无
*********************************************************************************************************
*/
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;  //临时变量

    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 18;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}

定时器0达到1ms之后会产生一个中断

在这个中断里面做了三件事
第一  作为时钟计数
第二  1ms刷新一个数码管
第三  10ms扫描一次按键
/*
*********************************************************************************************************
*        函 数 名: isr_timer_0
*        功能说明: 定时器中断服务函数
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void isr_timer_0(void)  interrupt 1  //默认中断优先级 1
{
        TH0 = T0RH;
        TL0 = T0RL;
        ms++;        
        display();  //1ms执行一次

        if(++intr == 10)  //1ms执行一次
        {
        intr = 0;
                key_flag = 1;  //10ms按键扫描标志位置1
    }
}

对于display();  //1ms执行一次这个函数是官方给的例程里面抄用的
/*
*********************************************************************************************************
*        函 数 名: display
*        功能说明: 显示函数数码管刷新
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void display(void)
{   
        XBYTE[0xE000] = 0xff;  //消隐
        
        XBYTE[0xC000] = (1<<dspcom);
    XBYTE[0xE000] = tab[dspbuf[dspcom]]; //段码

    if(++dspcom == 8){
        dspcom = 0;
    }   
}

key_flag = 1;  //10ms按键扫描标志位置1



每当这个标志位出现一次就会调用
read_key(void)   按键读取函数


读取对应的键值,看看是哪个按键按下来了


也是官方给的例程


/*
*********************************************************************************************************
*        函 数 名: read_key
*        功能说明: 读取键值
*        形    参:无
*        返 回 值: key_value
*********************************************************************************************************
*/
unsigned char read_key(void)
{
        
    unsigned char key_temp;

        key_temp = (P3&0x0f);
        
    if(key_temp != 0x0f) //有按键按下
        key_press++;
        else
                key_press = 0;  //抖动

    if(key_press == 5)
    {
                key_press = 0;
                key_re = 1;
                switch(key_temp)
        {
            case 0x0e:
                key_value = 1;  //
                break;               
            case 0x0d:
                key_value = 2;  //
                break;   
            case 0x0b:
                key_value = 3;  //
                break;   
            case 0x07:
                key_value = 4;  //
                break;
        }
    }
    //连续三次检测到按键被按下,并且该按键已经释放
    if((key_re == 1) && (key_temp == 0x0f))
    {
        key_re = 0;
        return key_value;
    }

    return 0xff;  //无按键按下或被按下的按键未被释放   
}






然后是配置波特率为了UART通信    ConfigUART(9600);也是封装好的函数
/*
*********************************************************************************************************
*        函 数 名: ConfigUART
*        功能说明: 串口配置函数,baud-通信波特率
*        形    参:baud
*        返 回 值: 无
*********************************************************************************************************
*/
void ConfigUART(unsigned int baud)
{
    SCON  = 0x50;  //配置串口为模式1
    TMOD &= 0x0F;  //清零T1的控制位
    TMOD |= 0x20;  //配置T1为模式2
    TH1 = 256 - (11059200/12/32)/baud;  //计算T1重载值
    TL1 = TH1;     //初值等于重载值
    ET1 = 0;       //禁止T1中断
    ES  = 1;       //使能串口中断
    TR1 = 1;       //启动T1
}

/*

然后配置完波特率以后每当uart接受数据就会产生下面这个UART中断在这个中断里面接受到的数据被保存到了全局变量RxdByte中了
为了以后调用(收到指令做出相应的灯亮)
/*
*********************************************************************************************************
*        函 数 名: InterruptUART
*        功能说明: UART中断服务函数
*        形    参:无
*        返 回 值: 无
*********************************************************************************************************
*/
void InterruptUART() interrupt 4
{
    if (RI)  //接收到字节
    {
        RI = 0;  //手动清零接收中断标志位
        RxdByte = SBUF;  //接收到的数据保存到接收字节变量中(电脑通过串口发给单片机的0XA0 0XA1 0XA2 0XA3..........0XAF这些控制灯变化的指令)
               
                if(uart_flag)
                {
                        uart_flag = 0;
                        uart_sendstring(str);
                }      如果收到的是B0这个指令的话,就发送当前时间到串口

    }
    if (TI)  //字节发送完毕
    {
        TI = 0;  //手动清零发送中断标志位
    }
}







扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式
我要创建版块 申请成为版主

论坛热帖

关闭

热门推荐上一条 /6 下一条

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