2019-10-01 13:09:17 weixin_41645129 阅读数 35
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

如何使用单片机开发小程序

单片机一般都是通过烧写hex或是bin文件来进行程序升级,这个方法是在8、16、32位单片机上常用的更新程序的方法。
这里实现单片机小程序的方法是通过在单片机上移植脚本来实现的。
目前我所了解的可以在单片机上跑的脚本有JerryScript、micropython、Lua。
因为脚本源码的代码量相对来说比较大,所以在8、16位的单片机一般不会使用到脚本开发。
在单片机上移植完后就是C、C++与脚本的互相通信,通过C、C++实现底层驱动、应用模块,将模块注册到脚本中,通过脚本调用。这样,只要通过更新文件系统中的脚本文件就可以实现在单片机上开发小程序,而不用通过烧写固件来升级程序。

2018-12-15 10:05:12 viewtoolsz 阅读数 1095
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏
1.jpg 
基于CAN总线的Bootloader,功能如下:
1、自动检测连接到CAN总线上的节点,并自动为每个节点分配一个唯一的地址;
2、自动检测节点是否在线,若离线则从列表中删除;
3、可以升级更新指定节点的程序,同时可以发送命令控制程序的执行;
目前程序基本功能已经完成,但是程序发送速度较慢,还需要进一步优化数据传输速度,等速度优化好了奉献单片机端源码与PC端源码。
2019-04-21 16:57:31 qq2874424207 阅读数 364
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

转载至http://www.51hei.com/bbs/dpj-146402-1.html
51黑本人账号
很简单的一个程序,大一的时候写的,
今天有人加我问这个问题,就把代码翻出来了,刚好分享出来
就是用外部中断检测判断状态的先后,来判断人的进出,在main里加减

单片机程序源码如下:

#include <reg52.h>
#include <string.h>
#define LCD1602_DB  P0
sbit red   = P2^0;  //红外1
sbit red1 = P2^1;   //红外2
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char flag1s = 0;
unsigned char flag2s = 0;
unsigned char code LedChar[] = { //数码管显示字符转换表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = { //数码管显示缓冲区,初值 0xFF 确保启动时都不亮
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char i = 0;
shu(unsigned char sec);
void delay(unsigned int i)
{
        while (i--);
}
shu(unsigned char sec)
{
LedBuff[0] = LedChar[sec%10];
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
LedBuff[3] = LedChar[sec/1000%10];
LedBuff[4] = LedChar[sec/10000%10];
LedBuff[5] = LedChar[sec/100000%10];
}
void main()
{
        unsigned int sec = 0,j = 0;    



red = 1;
    red1 = 1;
    ENLED = 0; 
ADDR3 = 1;
    TMOD = 0x01;
    TH0 = 0xFC;
    TL0 = 0x67;
    TR0 = 1;
    EA = 1;
    ET0 = 1;
    sec = 0;
    shu(sec);
    while(1)
    {         
       shu(sec);        
            if(flag1s == 1 )                  
            {
                    flag1s = 0;                        
                    sec++;
            
            }
            if(flag2s == 1 )                  
            {
                flag2s = 0;        
                    if(sec > 0)
                     sec--;
            } 
            shu(sec); 
    /*for(;sec<20;sec++)
               {itoa(sec, s);
            delay(100009);
            LcdShowStr(8, 0, s); } */
                                    


       }                
}
void InterruptTimer0() interrupt 1
{
    TH0 = 0xFC; //重新加载初值
    TL0 = 0x67;
    if (red == 0&&red1==1)  
    {
        delay(99);
                if(red1==0)
        flag1s = 1;
    }
    if (red1 == 0&&red == 1)  
    {
        delay(99);
                if(red == 0)
       flag2s = 1;
    }
        switch (i)
{
case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;
case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;
case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;
case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break; 
default: break;
}
}

很简单的代码,只能同时一人通过

2018-11-28 21:16:12 gavinpeng 阅读数 308
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

       调试单片机程序往往要用串口,光有输出也不够爽,我自己一直留着一份命令行代码,只要单片机资源足够就放上去。直接贴源码如下:


#define PARAM_MAX       (10)  /* 最多支持10个参数 */
#define CLI_MAX_LEN     (32)  /* 缓存大小,根据资源和最长命令行长度决定 */

/* 用户输入命令行 */
unsigned char g_input_buf[CLI_MAX_LEN];
unsigned char g_input_idx = 0;

/**********************************************************
函数描述 : 16进制字符转数值
输入参数 : c -- 字符,不作参数检查
输出参数 : 
返 回 值 : 数值,
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
unsigned char char_to_val(unsigned char c)
{
    if ( (c >= '0') && (c <= '9') )
        return c - '0';
    else if ( (c >= 'A') && (c <= 'Z') )
        return c - 'A' + 10;
    else if ( (c >= 'a') && (c <= 'z') )
        return c - 'a' + 10;
    else 
        return 0;
}

/**********************************************************
函数描述 : 字符串转数值
输入参数 : str -- 字符串
输出参数 : 
返 回 值 : 数值,
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
int str_to_int(unsigned char *str)
{
    int flag;
    int value = 0;
    unsigned char *p = str;

    if ( NULL == str )
        return 0;

    /* 16进制 */
    if ( (str[0] == '0') && ((str[1] == 'x') || (str[1] == 'X')) )
    {
        value = 0;
        p = &str[2];
        while ( *p )
        {
            value = value * 16 + char_to_val(*p);
            p++;
        }
        return value;
    }

    /* 10进制 */
    if ( str[0] == '-' )
        flag = -1;
    else
        flag = 1;

    value = 0;
    p = str;
    while ( *p ) 
        value = value * 10 + char_to_val(*p++);

    value = value * flag;

    return value;
}

/**********************************************************
函数描述 : 命令行测试
输入参数 : 
输出参数 : 
返 回 值 : 
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
void cmd_proc_test(int argc, char *argv[])
{
    int val;

    /* test val */
    if ( argc == 2 )
    {
	    val = str_to_int(argv[1]);
		printf("val = %d\r\n", val);
        return;
    }
}

/**********************************************************
函数描述 : 命令行菜单
输入参数 : 
输出参数 : 
返 回 值 : 
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
void cmd_usage(void)
{
    printf("\r\ncmd usage:\r\n");
	printf("? -- this menu\r\n");
	printf("ver -- show version\r\n");
	printf("test val -- how to use int\r\n");
}

/**********************************************************
函数描述 : 处理用户输入的命令
输入参数 : 
输出参数 : 
返 回 值 : 
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
void cmd_proc(void)
{
    int argc;
    char *argv[PARAM_MAX];
    char *p;

    /* 格式化字符串,把空格分开的词放入多个字符串 */
    p = (char*)g_input_buf;
    while ( *p && (' ' == *p) ) p++;

    if ( *p == '\0' )
        return;

    argc = 0;
    argv[argc++] = p;

    while ( *p )
    {
        if ( ' ' == *p ) 
        {
            *p++ = '\0';

            while ( *p && (' ' == *p) ) p++;

            if ( *p == '\0' )
                break;
            else
                argv[argc++] = p;

            if ( argc >= PARAM_MAX )
                return;
        }

        p++;
    }

    /* 处理消息 */
    if ( strcmp("?", argv[0]) == 0 )
	    cmd_usage();
	else if ( strcmp("ver", argv[0]) == 0 )
        printf("master ver: 1.0\r\n%s %s\r\n", __DATE__, __TIME__);
    else if ( strcmp("test", argv[0]) == 0 )
        cmd_proc_test(argc, argv);
    else
    {
        printf("unknown cmd: %s\r\n\r\n", argv[0]);
		cmd_usage();
    }

    return;
}

/**********************************************************
函数描述 : 分析输入的字符
输入参数 : buf -- 输入的字符首指针
           len -- 输入字符的长度
输出参数 : 
返 回 值 : 
作   者  : gavinpeng
时   间  : 2016.11.25
************************************************************/
void cmd_parse(char *buf, unsigned int len)
{
    int i = 0;
    char c;

    while ( i < len )
    {
		c = buf[i++];

		if ( c <= 0 )
			continue;

        switch ( c )
        {
            case '\r':
            case '\n': /* 0x0A, 回车的处理 */
                //g_input_buf[g_input_idx++] = '\r';
                printf("\r\n");
				g_input_buf[g_input_idx] = '\0';
				cmd_proc();
                g_input_idx = 0;
                break;

            case '\b': /* 0x08, 退格键 */
                if ( g_input_idx > 0 )
                {
                    g_input_idx--;
                    printf("\b \b");
                }
                g_input_buf[g_input_idx] = 0;
                break;

            default:
                /* 添加可见字符,其它忽略 */
                g_input_buf[g_input_idx++] = c;
				printf("%c", c);
                break;
        }
    }
}

/* 这里是串口中断函数 */
void uart1_ISR(void) interrupt
{
    // 从串口寄存器读出数据,放进全局buffer中
    if ( g_uart_rx_len < CLI_MAX_LEN )
        g_uart_db_rx_buf[g_uart_db_rx_len++] = uart_buf; 
}

void main(void)
{
    // 串口初始化
	
	// 主循环
	while ( 1 )
	{
	    if ( g_uart_db_rx_len ) 
        {
            cmd_parse(g_uart_db_rx_buf, g_uart_db_rx_len);
            g_uart_db_rx_len = 0;
        }
	}
}

有更好的,欢迎指出。

惯例要介绍一下自家的产品:

https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.594c1debREF8Mj&id=579411892273

 

2010-11-15 01:35:00 HNSD983704669 阅读数 1342
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3997 人正在学习 去看看 朱有鹏

前几天上单片机课时,老师给我们讲了 单片机 延时子程序,我也发现延时  程序 在单片机中 是非常 常用的,很重要

做作业 写延时程序的时候,感觉根本就不会写,写出来了也是套出来 的,而且 根本就不精确   于是 我就想  我要想一个通用的算法出来,写一个 51单片机 汇编 延时程序 源码生成器,以后 广大的 同学们 或者 单片机 开发者 没 就不用 去套就可以 得到 精确到 一个机器周期的 延时程序了,这个东西也已经做出来了,好了废话少说,现在 开始 和大家分享 我想出来的 算法

 

看几个例子:

一重循环:

   MOV  R0, #3
   DJNZ  R0,$

  

二重循环:

延时时间:T1=2*R0+1

 DELAY:      MOV    R1,#2
LOOP_2:   MOV    R0,#197
                 DJNZ   R0,$
                 DJNZ   R1,LOOP_2

                

 延时: T2=(2*R0+1+2)*R1+1

 

三重循环:

                 MOV      R2,#8
LOOP_3:   MOV    R1,#244
LOOP_4:   MOV    R0,#254
                 DJNZ   R0,$
                 DJNZ   R1,LOOP_4
                 DJNZ   R2,LOOP_3

延时:T3=(  (  (2*R0+1+2)*R1+1)  )+2)*R2+1

 

四重循环:

                 MOV    R3,#18
LOOP_5:   MOV    R2,#255
LOOP_6:   MOV    R1,#255
LOOP_7:   MOV    R0,#255
                DJNZ   R0,$
                DJNZ   R1,LOOP_7
                DJNZ   R2,LOOP_6
                DJNZ   R3,LOOP_5

可以归纳出:

 T2=(T1+2)*R1+1

 T3=(T2+2)*R2+1

 T4=(T3+2)*R3+1

 

仔细看一个  自己也可以再写一个 相信你一定能和我一样 发现这个规律

 

下变进行数学变换一下

将T1 代入T2 表达式

T2=1+3*R2+2*R0*R1

T3=1+3*(R2*R3+R3)+2*R0*R1*R2

T4=1+3*(R2*R3*R4+R3*R4+R4)+2*R0*R1*R2*R3

 

再进行一次归纳,或者说是抽象成一个通式:

 

这个公式是我总结出来的,接下来对公式进行说明:

 

这个是一个K元K次方程     表达式的单位是 机器周期 的个数

 

变量K:循环的次数 R 代表寄存器,下标代表 哪一个寄存器,如 R1

 

假设k=3   则会有 三个未知数 R1  R2  R3

 

大家看到最后加了一个2,原因是 我考虑到 一个子程序 结束时 会有一个返回指令 RET 占用两个机器周期

 

这个东西有什么用呢,很有用 一个未知数 就代表  一个 寄存器的 值 ,表达示结果 就是  用这几个 寄存器 写来来的 K重循环 所延时的机

 

器 周期数,即如果你要 延时 某个 时长(机器周期的整数倍时)  你只要解这个方程就 OK了, 不幸的是 这一个 方程 K个未知数,从数

 

学角度来说就无法解出来,也可能这个方程 根本 就找不到 K 个0—255的数 满足方程的,怎么办呢,是不是放弃呢,大家可以想一想,我

 

们现在是要做什么:

 

我要的是: 输入 要延时的   时长,和晶振   输出: 延时 汇编 源代码

 

你或许会想,也应该明白,如果这个方程 有解,并且你能解出来 那么这个问题就解 决了,而且 就用一个 汇编 循环(不是指一重循环)

 

就能够 达到延时 指定时间的效果,可是我们解不出来,(就算是用穷举法,由于方程可能无满足条件(0—255)的解,所以穷举不一定

 

行,而且很费时间,我已试过 晶振:12MHz  延时:60s  很久 都 穷举不完,下面就说我的方法

 

整体思想:象叠方块样的,大的  上面 叠 小的, 最上面叠  最小的,  当然 不能叠  太多了 ,要不然  汇编 代码 太多了不好 ,占用存储

 

空间

 

具体方法很简单

1、要据上面推导的公式,确定用机重循环可以搞定  即确定K

 

2、个寄存器全部置为255  从最高R8  开始  用二分法  确定  是一个  当R8=R8+1 时 T(k)>要延时时间  

R8=R8-1     T(k)<要延时的时间  且保证  R8=R8时 T(k)<要延时的时间

 直到  R0确定完毕

 

一次近似完毕

3 、 算去 误差 T

 

重复  上面三步  只到 K=0 即 最后 小于一重循环最小值  的机器周期数  的用 NOP 来延迟(也可能不需要,这个由你输入的 晶振 和

延时决定的)

 

从问题的 抽象 到 确定 算法 整个思 路 讲完了,很好的一个东东,可以精确到  每一个机器都期,如:晶振12MHz  就可以精确到 1us

 

 

 

 

 

没有更多推荐了,返回首页