扫地僧是怎样练成的,前辈学51单片机的感悟是怎么样的

发布者:DazzlingSpirit最新更新时间:2025-10-09 来源: bilibili关键字:51单片机 手机看文章 扫描二维码
随时随地手机看文章

从事安卓底层开发,工作八年,个人看法 。个人感脚51就是就是搞嵌入式第一门技术。把c语言,模数电,硬件画板等第一次联系起来。在学校的时候我们的学习路线是:

1 : 51单片机(大二上学期的时候,我感觉我还是接触的挺晚的,嵌入式)

2:stm32+ucos ii (大二下学期到大三下学期)

3:Arm+linux (大四到毕业)

4.安卓驱动 ,JNI(工作,mtk平台)

然并卵,这句话适合51,但是也是非常非常非常重要的基础。如果作为学生的话,参加比赛啥的51还是不够用的。51作为最简单的单片机,真真的简单。相比于linux 安卓真的太简单。

--------------------------------------------------

51单片如我上文所说的,学生党接触的第一款单片机,答主是电子信息工程毕业的,接触的第一个单片机也是51,然后是STM32.51和STM32 STM32比51 难一点,不过本质上都是单片机,STM32片上外设多很多,定时器啥的复杂复杂复杂复杂复杂多的多。STM32片上外设多,功能强大,可以说学了STM32之后基本上所有的单片机应该都能马上上手的,虽然我也只是只接触到51 和STM32.。大四全国电子设计大赛之后就再也没有接触到单片机了。后来就一直是linux,android。下面是我毕业论文的一部分。

-----------------------------------------------------

任何计算机系统都是软件和硬件的结合体,如果只有硬件而没有软件,则硬件是没有灵魂的躯壳;如果只有软件没有硬件,则软件就是一堆无用的字符。在底层硬件的基础上,操作系统覆盖一层驱动,屏蔽底层硬件的操作,通过特定的软件接口去操作底层硬件,用户在用户空间可以很容易的把软件设计目标放在策略与需求上,可以很方便的屏蔽掉底层实现,从而很好的完成客户功能需求。计算机系统是软件和硬件的结合体。而软件又分为应用层软件和驱动层软件。驱动层软件是应用层软件和底层硬件的纽带。通过驱动层软件实现对底层硬件屏蔽。

在裸机时代,比如单片机系统,程序员往往是直接操作硬件寄存器,直接设置硬件。而在Linux操作系统中,硬件驱动程序中实现对硬件直接操作,而用户空间,通过通用的系统调用接口,实现对硬件操作,应用程序没有直接操作底层设备,通过posix标准,应用程序的系统调用往往是被规定和限值,用户只能通过规定的接口实现对底层硬件的操作,导致了应用程序在类UINIX操作系统具有非常好的可移植性。

图2.1 直接操作硬件程序

上图2.1 是裸机时代,应用程序和硬件操作糅合在一起,应用程序和硬件操作高度耦合的框图,上述代码一般很难有良好的代码互用和移植性。往往从一个平台移植到另一个平台,甚至是同一平台不同硬件配置都要求很大的代码改动,另外从应用层来说,应用与驱动高度耦合,应用程序也几乎难以移植,甚至说是没有应用程序概念,原因在于应用与驱动的纠缠不清。

图2.2 无操作系统应用程序和设备驱动程序关系

上图2.2所示,良好的裸机代码框架,设备驱动层和应用层之间有良好的分层思想,用户可以较好的实现策略和需求,例如:客户要求实现流水灯程序,程序员在底层机制实现(硬件操作)的基础下,可以充分在用户应用程序中把主要精力方法流水灯的实现,即策略。但是在良好的裸机程序设计,代码移植性可能从一个平台移植到另外一平台只需要修改少量的底层驱动,例如:LED_ON()的实现。但是在用户空间,没有系统调用概念,函数接口千差万别。应用程序移植性差。

图2.3 Linux系统调用框图

操作系统中,需求决定应用程序,通过系统调用,调用底层驱动,此外,在驱动程序中,把一部分公用的驱动接口抽象出来,如此,程序员只需修改很少量的驱动资源,形成特定的驱动框架。导致用户只需添加专用的硬件属性作为平台资源,在内核中获取资源,大大解放了设备驱动开发,提高了设备驱动的通用型。在用户空间,由于遵循posix标准,类UNIX操作系统中,所有操作接口基本一样,从而方便了应用程序的移植,应用程序几乎不要做修改。如图2.3所示。

Linux操作系统对于所有的硬件都是当做一个文件来操作:一切设备皆文件。Linux设备文件一般分为字符设备,块设备,网络设备。在Linux系统中,除了网络设备之外,所有的设备都被映射到Linux的文件系统中。如图2.4所示。

图2.4 Linux操作系统与应用程序关系

-----------------------------------------------------

讲讲51,linux,安卓之间的差别。先申明一下,我是实际工作中没有使用过单片机,我使用单片机仅仅是用来参加全国电子设计大赛。工作主要在android driver这一块。我们这一行很多人说单片机是有瓶颈的,我也不是很清楚。但是实话实说,这鸟东西太简单了,没啥技术含量的,你要之后android的庞大。

欢迎点赞。后面会说说android,linux,51,32单片机之间的联系与学习方法,虽然我也是菜鸟,如果你现在看不懂也没关系,有个映像就行。以后就有方向去学习了。想当初我真的是一个人孤孤学习linux

===================================================补充一个:单片机要点亮一个led等,同样在安卓上你点亮一个灯也要驱动的,不然怎么亮呢,只是我们只看到了app。 背后驱动,怎么实现的,安卓架构,跟单片机有啥区别,相同的地方。其实手机arm芯片跟单片机都是嵌入式微处理器,单片机叫做微控制器。高通,mtk啥的也是嵌入式微处理器~都是一样的~但是难度你想想看就知道了。

51单片机大家都知道了,裸机,直接操作硬件,直观,简单,没有框架,没有系统。

STM32,可以学习一下RTOS了,实时的小系统,ucos II等等许多实时系统,STM32+ucos II这种组合学习方式还是挺好的。STM32比较难的在我印象中一个是时钟树,因为我们从51,没有时钟树的概念12M晶振,时钟不要你配置,而比较新的ARM框架,外设都是有时钟的。可能刚刚接触概念不是很清楚,但是也是很简单的。另外一个是定时器,什么输入捕获模式,定时器模式,编码器模式。。。。。强大的多,比起51。总的来说还是简单的。因为是没有框架的原因,代码量真的很少。你要知道,MTK android 5.1 所有的东西加起来 10G多,包括bootloader,linux kernel,android framework ,定制的部分。等等。我们接触的就那些目录,当你去看C++,java代码时,你就知道面向过程的代码真的很容易看。可能有些朋友不知道android的框架,以及android 与linux之间的关系,以及linux驱动与裸机的关系,联系与区别。你现在只要知道linux驱动比较大,android框架更大。单片机简单。单片机一般是C语言,而android一般涉及三种语言:底层linux内核C,中间的JNI层是C++,framework和app是java。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

学过51单片机的朋友知道,我们要点亮一个LED灯,是这样子的P0 = xxx ,我们就点亮了一个,好。一烧写,好,灯亮了。linux,上我们要亮一个灯,有点难了,有了操作系统,没那么容易了。一般人搞不定了。好,到android,更加难了。但是你想一想手机芯片也是ARM。亮灯这种肯定都是CPU的管脚操作。上了系统了,难了,点个灯都费劲的。本质上是一样的。很多人都知道单片机有瓶颈的。原因是会点硬件,会点C,轻轻松松就可以亮灯的。入门容易。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我举一个小的例子说明一下51,linux,android三者的之间的差别。你就知道是啥区别。下面是51单片机:

大概是这样:

intmain(void) //一个main函数 搞定{P0 =0xxx;while(1);return0;}

linux:

驱动程序:#include#include#include //file_operatios#include//class_create/device_create#include //kmalloc#include //ioremap#include#include"led.h"struct s5pv210_device *s5pv210_dev;

volatileunsignedlong*gpc0con =NULL;volatileunsignedlong*gpc0dat =NULL;

staticintled_open(struct inode *inode, struct file *file){printk(KERN_INFO"%s()-%dn", __func__, __LINE__);

/*初始化GPC0_3,GPC0_4引脚功能为输出功能*/*gpc0con &=~((0xf<<12)|(0xf<<16));*gpc0con |= ((0x1<<12)|(0x1<<16));return0;}

staticintled_close(struct inode *inode, struct file *file){printk(KERN_INFO"%s()-%dn", __func__, __LINE__);//iounmap(S5PV210_PA_GPC0CON);return0;}

static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *offset){printk(KERN_INFO"%s()-%dn", __func__, __LINE__);

return0;}

//write(fd, &val, 4)staticssize_t led_write(struct file *file, constchar __user *buf, size_t count, loff_t *offset){int ret;unsignedint val;printk(KERN_INFO"%s()-%dn", __func__, __LINE__);

/*获取用户空间数据*/ret = copy_from_user(&val,buf,count);if(ret){printk(KERN_ERR"copy data from user failed!n");return-ENODATA;}

printk(KERN_INFO"copy data from user: val=%dn",val);

if(val){//点亮LED*gpc0dat |= ((0x1<<3)|(0x1<<4));}else{//熄灭LED*gpc0dat &=~((0x1<<3)|(0x1<<4));

}return ret?0:count;}

staticstruct file_operations led_fops={.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_close,

};

staticint __init led_init(void){int ret;printk(KERN_INFO"%s()-%dn", __func__, __LINE__);s5pv210_dev = kmalloc(sizeof(struct s5pv210_device),GFP_KERNEL);if(s5pv210_dev==NULL){printk(KERN_INFO"no memory malloc for s5pv210_dev!n");return-ENOMEM;}

/*注册*/led_major = register_chrdev(0,"led",&led_fops);if(led_major<0){printk(KERN_INFO"register major failed!n");ret =-EINVAL;goto err1;}

/*创建设备文件*/s5pv210_dev->led_class = class_create(THIS_MODULE,"led_class");if (IS_ERR(s5pv210_dev->led_class)) {printk(KERN_ERR "class_create() failed for led_classn");ret =-EINVAL;goto err2;}

s5pv210_dev->led_device = device_create(s5pv210_dev->led_class,NULL,MKDEV(led_major,0),NULL,"led");if (IS_ERR(s5pv210_dev->led_device)) {printk(KERN_ERR "device_create failed for led_devicen");ret =-ENODEV;goto err3;}

/*将物理地址映射为虚拟地址*/gpc0con = ioremap(S5PV210_PA_GPC0CON,8);if(gpc0con==NULL){printk(KERN_INFO"ioremap failed!n");ret =-ENOMEM;goto err4;}gpc0dat = gpc0con +1;

return0;err4:device_destroy(s5pv210_dev->led_class,MKDEV(led_major,0));err3:class_destroy(s5pv210_dev->led_class);err2:unregister_chrdev(led_major,"led");err1:kfree(s5pv210_dev);return ret;}staticvoid __exit led_exit(void){printk(KERN_INFO"%s()-%dn", __func__, __LINE__);unregister_chrdev(led_major,"led");device_destroy(s5pv210_dev->led_class,MKDEV(led_major,0));class_destroy(s5pv210_dev->led_class);iounmap(gpc0con);kfree(s5pv210_dev);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");

应用程序:

#include

#include

#include

#include

#include

#include

#include

#include

/*

** ./led_test on 点亮LED

** ./led_test off 熄灭LED

*/

int main(int argc, char **argv)

{

int fd;

int val =0;

fd = open("/dev/led", O_RDWR);

if(fd

{

perror("open failed!n");

exit(1);

}

if(strcmp(argv[1], "on")==0)

{

val = 1;

}

else

{

val = 0;

}

if(write(fd, &val, 4)!=4)

{

perror("write failed!n");

exit(1);

}

close(fd);

return 0;

}

android:

不知道大家清不清楚android与linux之间的关系。

android是基于linux内核的,linux操作系统的5大组件:驱动,内存管理,文件系统,进程管理,网络套接字。android是基于linux kernel上的,大家平时只看到了app。app是java语言的,其实每运行一个java应用程序,实际上是fork一个linux应用程序。android四大组件,activity,service,Broadcast Receiver,Content Provider。这是android的主要框架,java应用开发是基于这开发的。android平台是基于linux 内核的。在linux运行之后才建立起java世界。

直接上代码:上面的linux的驱动在android是一样的,适用于android。驱动ok之后是应用层了,也就是应用程序。我下面就是最直接的应用,不包含任何android框架性的东西,大家可以直接看到,应用app->jni->linux驱动这三层调用关系。下面是jni代码是c++;

#define LOG_TAG "led-jni-log"#include#include "jni.h"#include#include#include#include#include#include#includestaticint fd =-1;

jint open_led(JNIEnv *env, jobject thiz){LOGD("$$$%sn", __FUNCTION__);fd = open("/dev/led1", O_RDWR);if(fd <0){LOGE("open : %sn", strerror(errno));return-1;}

return0;}

jint led_on(JNIEnv *env, jobject thiz){LOGD("$$$%sn", __FUNCTION__);int val =1;jint ret =0;ret = write(fd, &val, 4);if(ret !=4){LOGE("write : %sn", strerror(errno));return-1;}return0;}

jint led_off(JNIEnv *env, jobject thiz){LOGD("$$$%sn", __FUNCTION__);int val =0;jint ret =0;ret = write(fd, &val, 4);if(ret !=4){LOGE("write : %sn", strerror(errno));return-1;}return0;}

jint close_led(JNIEnv *env, jobject thiz){LOGD("$$$%sn", __FUNCTION__);if(fd >0)close(fd);return0;}

static JNINativeMethod myMethods[] ={{"openDev", "()I", (void*)open_led},{"onDev", "()I", (void*)led_on},{"offdev", "()I", (void*)led_off},{"closeDev", "()I", (void*)close_led},};

jint JNI_OnLoad(JavaVM * vm, void* reserved){JNIEnv *env =NULL;jint ret =-1;ret = vm->GetEnv((void**)&env, JNI_VERSION_1_4);if(ret <0){LOGE("GetEnv errorn");return-1;}

jclass myclz = env->FindClass("com/ledtest/LedActivity");if(myclz ==NULL){LOGE("FindClass errorn");return-1;}ret = env->RegisterNatives(myclz, myMethods, sizeof(myMethods)/sizeof(myMethods[0]));if(ret <0){LOGE("RegisterNatives errorn");return-1;}

return JNI_VERSION_1_4;}

然后是java app:

packagecom.ledtest;

importandroid.os.Bundle;importandroid.app.Activity;importandroid.util.Log;importandroid.view.Menu;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;

publicclassLedActivityextends Activity {

final String TAG ="LedActivity";public Button btn_on =null;public Button btn_off =null;

publicvoidinit(){btn_on =(Button)this.findViewById(R.id.btn1);btn_on.setOnClickListener(clickListener);

btn_off =(Button)this.findViewById(R.id.btn2);btn_off.setOnClickListener(clickListener);}

[1] [2]
关键字:51单片机 引用地址:扫地僧是怎样练成的,前辈学51单片机的感悟是怎么样的

上一篇:学51单片机原理入门知识点,复位时钟和时序(一)
下一篇:基于51单片机的16键电子琴音乐盒设计proteus仿真原理图程序

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved