主页 > 单片机单片机如何用C程序编程?

单片机如何用C程序编程?

一、单片机如何用C程序编程?

单片机支持汇编编程的C51编程。

1、汇编编程,传统的汇编代码。

缺点:可读性不强,优点:代码精简2、C51编程,使用专用C语言编程。

缺点:代码不精简,优点:可读性强。KeilC和IAR等编译软件,同时支持C51和汇编代码。

二、单片机中断程序的编程实例?

下面是一个简单的单片机中断程序的编程实例,以8051单片机为例:

```assembly

ORG 0H ; 程序从地址0开始

MOV A, #0FFH ; 将A寄存器初始化为0xFF

MOV P1, A ; 将A寄存器的值输出到P1口

MOV TMOD, #20H ; 设置定时器1为模式2

MOV TH1, #0FDH ; 设置定时器1的初始值高字节为0xFD

MOV TL1, #0FDH ; 设置定时器1的初始值低字节为0xFD

SETB TR1 ; 启动定时器1

MAIN:

JNB TF1, MAIN ; 等待定时器1中断发生

CLR TF1 ; 清除定时器1溢出标志

CPL P1 ; 反转P1口的值

SJMP MAIN ; 无限循环

ORG 1BH ; 定时器1中断服务子程序的入口地址

INTERRUPT:

PUSH ACC ; 保存ACC寄存器的值

PUSH PSW ; 保存PSW寄存器的值

CLR TR1 ; 停止定时器1

MOV A, #0FFH ; 将A寄存器重新加载为0xFF

MOV P1, A ; 将A寄存器的值重新输出到P1口

POP PSW ; 恢复PSW寄存器的值

POP ACC ; 恢复ACC寄存器的值

RETI ; 中断服务子程序结束,返回主程序

```

在上面的示例中,我们使用了8051单片机的定时器1作为中断源。程序初始化了定时器1,并设置了适当的初始值和模式。在主程序中,我们等待定时器1的溢出中断发生,并在中断服务子程序中进行相应的操作。在中断服务子程序中,我们首先保存寄存器的状态,然后执行一些特定的操作,最后恢复寄存器的状态并返回主程序。

三、单片机时钟汇编程序:学习如何编写单片机时钟程序

单片机时钟汇编程序简介

单片机时钟汇编程序是嵌入式系统中常见的应用之一,通过学习和掌握单片机时钟程序的编写,可以帮助开发者更好地理解单片机的工作原理和应用。

单片机时钟原理

单片机时钟通常由晶体振荡器提供时钟信号,通过计数器来实现时钟的计时功能。在汇编语言中,可以通过控制寄存器和定时器来精确控制时钟的频率和计时过程。

编写单片机时钟汇编程序步骤

学习编写单片机时钟汇编程序的步骤如下:

  • 初始化定时器:首先需要初始化定时器,设置时钟的频率和计时的时间间隔。
  • 编写中断服务程序:在汇编程序中编写中断服务程序,用于处理定时器中断事件。
  • 启用定时器中断:启用定时器中断,使单片机在计时达到设定值时触发中断处理。
  • 编写主程序:编写主程序,控制时钟的显示和更新逻辑。

单片机时钟汇编程序示例

以下是一个简单的单片机时钟汇编程序示例,用于每隔一定时间更新时钟的显示:

    
    ; 初始化定时器
    ; 编写中断服务程序
    ; 启用定时器中断
    ; 编写主程序
    
    

总结

通过编写单片机时钟汇编程序,可以深入理解单片机的工作原理、中断处理机制以及时序控制方法,为后续嵌入式系统开发打下坚实的基础。

感谢您阅读本文,希望通过学习单片机时钟汇编程序,可以更好地理解和掌握单片机的应用。

四、51单片机数码管显示程序编程?

KEYVAL EQU 30H

KEYTM EQU 31H

KEYSCAN EQU 32H

DAT EQU 33H

SCANLED EQU 39H

CLK EQU 77H

SEC EQU 78H

MIN EQU 79H

HOUR EQU 7AH

PAUSE BIT 00H

DOT BIT 01H

ORG 0000H

LJMP MAIN

ORG 000BH

LJMP T0ISR ;50ms定时

ORG 001BH

LJMP T1ISR ;扫描显示

ORG 0030H

MAIN:

MOV SP,#5FH

MOV TMOD,#11H

MOV TH0,#03CH

MOV TL0,#0B0H

MOV TH1,#0ECH

MOV TL1,#078H

MOV KEYVAL,#0

MOV SCANLED,#0

MOV 33H,#10H

MOV 34H,#10H

MOV 35H,#10H

MOV 36H,#10H

MOV 37H,#10H

MOV 38H,#10H

MOV SEC,#0

MOV MIN,#0

MOV HOUR,#0

MOV CLK,#0

CLR PAUSE

SETB EA

SETB ET1

SETB TR1

LOOP:

LCALL KEYSEL

MOV A,KEYVAL

CJNE A,#0FFH,LOOP1

SJMP LOOP

LOOP1:

CJNE A,#10,LOOP2 ;“ON”启动

SETB TR0

SETB ET0

SETB PAUSE

SJMP LOOP

LOOP2:

CJNE A,#11,LOOP3 ;“=”清零

MOV SEC,#0

MOV MIN,#0

MOV HOUR,#0

LCALL DISCHG

SJMP LOOP

LOOP3:

CJNE A,#15,LOOP4 ;“+”暂停

CLR TR0

CLR ET0

CLR PAUSE

SJMP LOOP

LOOP4:

CJNE A,#14,LOOP5 ;“-”清显示暂停

MOV 33H,#10H

MOV 34H,

五、单片机汇编程序和C程序哪个容易出bug?

c程序更容易出现bug,高级语言在编写的时候容易出现赋值,指针指向的问题有时候会很容易出错

六、汇编程序如何烧写到单片机里?

汇编语言烧到单片机 的过程 ( 不同系列的单片机有所不同) 汇编程序 ---> 汇编语言编译器 ---> 单片机烧写器 ---> 单片机 编写 软件 软件+硬件 单片机

七、单片机编程软件有什么?

比较有名的keil,一般你买的单片机都会有配套的开发环境,这个不用担心,

编程语言c居多,不过你要是想用汇编,也是可以的,汇编可以熟悉学习下底层原理,实际的开发一般还是用c的

八、单片机编程人工智能?

摘要:不知道大家有没有这样一种感觉,就是感觉自己玩单片机还可以,各个功能模块也都会驱动,但是如果让你完整的写一套代码,却无逻辑与框架可言,上来就是开始写!东抄抄写抄抄。说明编程还处于比较低的水平,那么如何才能提高自己的编程水平呢?学会一种好的编程框架或者一种编程思想,可能会受用终生!比如模块化编程,框架式编程,状态机编程等等,都是一种好的框架。

今天说的就是状态机编程,由于篇幅较长,大家慢慢欣赏。那么状态机是一个这样的东东?状态机(state machine)有5个要素,分别是状态(state)、迁移(transition)、事件(event)、动作(action)、条件(guard)。

什么是状态机?

状态机是一个这样的东东:状态机(state machine)有 5 个要素,分别是状态(state)、迁移(transition)、事件(event)、动作(action)、条件(guard)。

状态:一个系统在某一时刻所存在的稳定的工作情况,系统在整个工作周期中可能有多个状态。例如一部电动机共有正转、反转、停转这 3 种状态。

一个状态机需要在状态集合中选取一个状态作为初始状态。

迁移:系统从一个状态转移到另一个状态的过程称作迁移,迁移不是自动发生的,需要外界对系统施加影响。停转的电动机自己不会转起来,让它转起来必须上电。

事件:某一时刻发生的对系统有意义的事情,状态机之所以发生状态迁移,就是因为出现了事件。对电动机来讲,加正电压、加负电压、断电就是事件

动作:在状态机的迁移过程中,状态机会做出一些其它的行为,这些行为就是动作,动作是状态机对事件的响应。给停转的电动机加正电压,电动机由停转状态迁移到正转状态,同时会启动电机,这个启动过程可以看做是动作,也就是对上电事件的响应。

条件:状态机对事件并不是有求必应的,有了事件,状态机还要满足一定的条件才能发生状态迁移。还是以停转状态的电动机为例,虽然合闸上电了,但是如果供电线路有问题的话,电动机还是不能转起来。

只谈概念太空洞了,上一个小例子:一单片机、一按键、俩 LED 灯(记为L1和L2)、一人, 足矣!

【学习交流群】不知道怎么学?遇到问题没人问?到处找资料?邀请你加入我的嵌入式物联网单片机学习交流群,群内气氛活跃,大咖小白、在职、学生都有,还有群友整理收集的100G教程资料,点击下方进群占位。(点击跳转到群二维码,请放心点击!)

知乎-嵌入式物联网单片机学习交流群

规则描述:

1、L1L2状态转换顺序OFF/OFF--->ON/OFF--->ON/ON--->OFF/ON--->OFF/OFF

2、通过按键控制L1L2的状态,每次状态转换需连续按键5

3、L1L2的初始状态OFF/OFF

下面这段程序是根据功能要求写成的代码。

程序清单List1:

void main(void)
{
 sys_init();
 led_off(LED1);
 led_off(LED2);
 g_stFSM.u8LedStat = LS_OFFOFF;
 g_stFSM.u8KeyCnt = 0;
 while(1)
 {
  if(test_key()==TRUE)
  {
   fsm_active();
  }
  else
  {
   ; /*idle code*/
  }
 }
}
void fsm_active(void)
{
 if(g_stFSM.u8KeyCnt > 3) /*击键是否满 5 次*/
 {
  switch(g_stFSM.u8LedStat)
  {
   case LS_OFFOFF:
    led_on(LED1); /*输出动作*/
    g_stFSM.u8KeyCnt = 0;
    g_stFSM.u8LedStat = LS_ONOFF; /*状态迁移*/
    break;
   case LS_ONOFF:
    led_on(LED2); /*输出动作*/
    g_stFSM.u8KeyCnt = 0;
    g_stFSM.u8LedStat = LS_ONON; /*状态迁移*/
    break;
   case LS_ONON:
    led_off(LED1); /*输出动作*/
    g_stFSM.u8KeyCnt = 0;
    g_stFSM.u8LedStat = LS_OFFON; /*状态迁移*/
    break;
   case LS_OFFON:
    led_off(LED2); /*输出动作*/
    g_stFSM.u8KeyCnt = 0;
    g_stFSM.u8LedStat = LS_OFFOFF; /*状态迁移*/
    break;
   default: /*非法状态*/
    led_off(LED1);
    led_off(LED2);
    g_stFSM.u8KeyCnt = 0;
    g_stFSM.u8LedStat = LS_OFFOFF; /*恢复初始状态*/
    break;
  }
 }
 else
 {
  g_stFSM.u8KeyCnt++; /*状态不迁移,仅记录击键次数*/
 }
}

实际上在状态机编程中,正确的顺序应该是先有状态转换图,后有程序,程序应该是根据设计好的状态图写出来的。不过考虑到有些童鞋会觉得代码要比转换图来得亲切,我就先把程序放在前头了。

这张状态转换图是用UML(统一建模语言)的语法元素画出来的,语法不是很标准,但拿来解释问题足够了。

圆角矩形代表状态机的各个状态,里面标注着状态的名称。

带箭头的直线或弧线代表状态迁移,起于初态,止于次态。

图中的文字内容是对迁移的说明,格式是:事件[条件]/动作列表(后两项可选)。

“事件[条件]/动作列表”要说明的意思是:如果在某个状态下发生了“事件”,并且状态机

满足“[条件]”,那么就要执行此次状态转移,同时要产生一系列“动作”,以响应事件。在这个例子里,我用“KEY”表示击键事件。

图中有一个黑色实心圆点,表示状态机在工作之前所处的一种不可知的状态,在运行之前状态机必须强制地由这个状态迁移到初始状态,这个迁移可以有动作列表(如图1所示),但不需要事件触发。

图中还有一个包含黑色实心圆点的圆圈,表示状态机生命周期的结束,这个例子中的状态机生生不息,所以没有状态指向该圆圈。

关于这个状态转换图就不多说了,相信大家结合着上面的代码能很容易看明白。现在我们再聊一聊程序清单List1。

先看一下fsm_active()这个函数,g_stFSM.u8KeyCnt = 0;这个语句在switch—case里共出现了 5 次,前 4 次是作为各个状态迁移的动作出现的。从代码简化提高效率的角度来看,我们完全可以把这 5 次合并为 1 次放在 switch—case 语句之前,两者的效果是完全一样的,代码里之所以这样啰嗦,是为了清晰地表明每次状态迁移中所有的动作细节,这种方式和图2的状态转换图所要表达的意图是完全一致的。

再看一下g_stFSM这个状态机结构体变量,它有两个成员:u8LedStatu8KeyCnt。用这个结构体来做状态机好像有点儿啰嗦,我们能不能只用一个像 u8LedStat 这样的整型变量来做状态机呢?

当然可以!我们把图 2中的这 4 个状态各自拆分成 5 个小状态,这样用 20 个状态同样能实现这个状态机,而且只需要一个 unsigned char 型的变量就足够了,每次击键都会引发状态迁移, 每迁移 5 次就能改变一次 LED 灯的状态,从外面看两种方法的效果完全一样。

假设我把功能要求改一下,把连续击键5次改变L1L2的状态改为连续击键100次才能改变L1L2的状态。这样的话第二种方法需要4X100=400个状态!而且函数fsm_active()中的switch—case语句里要有400个case,这样的程序还有法儿写么?!

同样的功能改动,如果用g_stFSM这个结构体来实现状态机的话,函数fsm_active()只需要将if(g_stFSM.u8KeyCnt>3)改为if(g_stFSM.u8KeyCnt > 98)就可以了!

g_stFSM结构体的两个成员中,u8LedStat可以看作是质变因子,相当于主变量;u8KeyCnt可以看作是量变因子,相当于辅助变量。量变因子的逐步积累会引发质变因子的变化。

g_stFSM这样的状态机被称作Extended State Machine,我不知道业内正规的中文术语怎么讲,只好把英文词组搬过来了。

2、状态机编程的优点

说了这么多,大家大概明白状态机到底是个什么东西了,也知道状态机化的程序大体怎么写了,那么单片机的程序用状态机的方法来写有什么好处呢?

(1)提高CPU使用效率

话说我只要见到满篇都是delay_ms()的程序就会蛋疼,动辄十几个ms几十个ms的软件延时是对CPU资源的巨大浪费,宝贵的CPU机时都浪费在了NOP指令上。那种为了等待一个管脚电平跳变或者一个串口数据而岿然不动的程序也让我非常纠结,如果事件一直不发生,你要等到世界末日么?

把程序状态机化,这种情况就会明显改观,程序只需要用全局变量记录下工作状态,就可以转头去干别的工作了,当然忙完那些活儿之后要再看看工作状态有没有变化。只要目标事件(定时未到、电平没跳变、串口数据没收完)还没发生,工作状态就不会改变,程序就一直重复着“查询—干别的—查询—干别的”这样的循环,这样CPU就闲不下来了。在程序清单 List3 中,if{}else{}语句里else下的内容(代码中没有添加,只是加了一条/*idle code*/的注释示意)就是上文所说的“别的工作” 。

这种处理方法的实质就是在程序等待事件的过程中间隔性地插入一些有意义的工作,好让CPU不是一直无谓地等待。

(2) 逻辑完备性

我觉得逻辑完备性是状态机编程最大的优点

不知道大家有没有用C语言写过计算器的小程序,我很早以前写过,写出来一测试,那个惨不忍睹啊!当我规规矩矩的输入算式的时候,程序可以得到正确的计算结果,但要是故意输入数字和运算符号的随意组合,程序总是得出莫名其妙的结果。

后来我试着思维模拟一下程序的工作过程,正确的算式思路清晰,流程顺畅,可要碰上了不规矩的式子,走着走着我就晕菜了,那么多的标志位,那么多的变量,变来变去,最后直接分析不下去了。

很久之后我认识了状态机,才恍然明白,当时的程序是有逻辑漏洞的。如果把这个计算器程序当做是一个反应式系统,那么一个数字或者运算符就可以看做一个事件,一个算式就是一组事件组合。对于一个逻辑完备的反应式系统,不管什么样的事件组合,系统都能正确处理事件,而且系统自身的工作状态也一直处在可知可控的状态中。反过来,如果一个系统的逻辑功能不完备,在某些特定事件组合的驱动下,系统就会进入一个不可知不可控的状态,与设计者的意图相悖。

状态机就能解决逻辑完备性的问题。

状态机是一种以系统状态为中心,以事件为变量的设计方法,它专注于各个状态的特点以及状态之间相互转换的关系。状态的转换恰恰是事件引起的,那么在研究某个具体状态的时候,我们自然而然地会考虑任何一个事件对这个状态有什么样的影响。这样,每一个状态中发生的每一个事件都会在我们的考虑之中,也就不会留下逻辑漏洞。

这样说也许大家会觉得太空洞,实践出真知,某天如果你真的要设计一个逻辑复杂的程序,

我保证你会说:哇!状态机真的很好用哎!

(3)程序结构清晰

用状态机写出来的程序的结构是非常清晰的。

程序员最痛苦的事儿莫过于读别人写的代码。如果代码不是很规范,而且手里还没有流程图,读代码会让人晕了又晕,只有顺着程序一遍又一遍的看,很多遍之后才能隐约地明白程序大体的工作过程。有流程图会好一点,但是如果程序比较大,流程图也不会画得多详细,很多细节上的过程还是要从代码中理解

相比之下,用状态机写的程序要好很多,拿一张标准的UML状态转换图,再配上一些简明的文字说明,程序中的各个要素一览无余。程序中有哪些状态,会发生哪些事件,状态机如何响应,响应之后跳转到哪个状态,这些都十分明朗,甚至许多动作细节都能从状态转换图中找到。可以毫不夸张的说,有了UML状态转换图,程序流程图写都不用写。

九、单片机数码管显示汇编程序

单片机数码管显示汇编程序

本文将讨论单片机数码管显示的汇编程序。数码管在嵌入式系统中广泛应用,用于显示各种信息,如时间、计数器值、测量数值等。

在嵌入式系统中,单片机是一种集成电路芯片,它包含了处理器核心、存储器、输入输出接口等功能模块。通过编程,我们可以控制单片机的工作,实现各种功能。

数码管是一种常见的数字显示设备,它由七段LED组成,每个LED代表一个段,可以显示0到9的数字和一些字母。使用单片机控制数码管显示,需要编写相应的汇编程序。

以下是一个简单的单片机数码管显示的汇编程序示例:

MOV P1, #0FFH ; 设置P1口为高电平,用于驱动数码管的段 MOV P2, #0F0H ; 设置P2口为低电平,用于驱动数码管的位 MOV R0, #0AH ; 设置计数器初值为10,用于循环显示0到9的数字 MOV R1, #00H ; 设置R1寄存器为0,用于存储要显示的数字 LOOP: ; 循环开始 MOV A, R1 ; 将R1寄存器中的值赋给累加器A ADD A, #30H ; 将A的ASCII码值加上30H,转换成显示的字符 ACALL DISPLAY ; 调用显示数字的子程序 INC R1 ; R1寄存器加1 CJNE R1, R0, LOOP ; 如果R1寄存器的值不等于R0寄存器的值,则跳转到LOOP SJMP LOOP ; 无条件跳转到LOOP DISPLAY: ; 显示数字的子程序开始 MOV P0, A ; 将累加器A的值赋给P0口,用于驱动数码管的段显示 MOV P2, #0FH ; 将P2口的低4位设置为高电平,选中其中一个数码管显示 ACALL DELAY ; 延时一段时间,控制数码管显示的刷新频率 MOV P2, #0F0H ; 将P2口的低4位设置为低电平,关闭所有数码管的显示 RET ; 子程序返回 DELAY: ; 延时子程序开始 MOV R2, #0FFH ; 设置计数器初值为255 AGAIN: ; 循环开始 MOV R3, #0FH ; 设置R3寄存器初值为15 INNER: ; 内部循环开始 DJNZ R3, INNER ; R3寄存器减1,如果不等于0则跳转到INNER DJNZ R2, AGAIN ; R2寄存器减1,如果不等于0则跳转到AGAIN RET ; 子程序返回

上述汇编程序实现了显示0到9的数字。程序首先设置端口P1为高电平,用于驱动数码管的段,然后设置端口P2为低电平,用于驱动数码管的位。接着,将计数器初值设置为10,R1寄存器设置为0,用于存储要显示的数字。然后通过循环将R1寄存器的值赋给累加器A,转换成对应的ASCII码值,并调用显示数字的子程序进行显示。每次循环结束,R1寄存器加1,直到R1寄存器的值等于计数器的值。在显示数字的子程序中,将累加器A的值赋给端口P0,用于驱动数码管的段显示。然后选择一个数码管进行显示,延时一段时间,再关闭所有数码管的显示。延时子程序通过两个嵌套的循环实现。

通过上述汇编程序,我们可以实现简单的单片机数码管显示。在实际应用中,我们可以根据需要进行修改和扩展,实现更复杂的功能。

总结

本文介绍了单片机数码管显示的汇编程序。通过编写相应的汇编程序,我们可以控制单片机驱动数码管显示各种信息。数码管在嵌入式系统中具有广泛的应用,是数字显示的常见设备。

汇编语言是一种低级的程序设计语言,直接面向处理器。掌握汇编语言可以更加深入地理解计算机的工作原理,并能够编写高效、精确的程序。汇编程序可以直接控制硬件,因此在一些对性能要求较高的场景中仍然得到广泛应用。

希望本文对读者理解单片机数码管显示的汇编程序有所帮助,同时也能够引发更多关于嵌入式系统和汇编语言的思考。

十、51单片机数码管汇编程序

大家好,今天我想与大家分享的是关于51单片机数码管汇编程序的内容。作为嵌入式系统开发的一部分,掌握单片机的编程是非常重要的。其中,数码管作为一种常见的显示器件,被广泛应用于各种电子设备中。掌握数码管的编程,能够实现对数字的显示和动态显示,为我们设计出更多样化、更丰富的项目奠定基础。

51单片机是一种基于8051核心的单片机,其有着广泛的应用领域。在数码管的编程中,我们首先需要了解数码管的工作原理和接口。数码管是由多个发光二极管组成的,其每一个发光二极管称为一个段,而不同的段又可以组合在一起来显示不同的数字、字母或符号。数码管通常由四位共阳(共阴)数码管组成,每一位数码管可以显示0-9的数字。

在进行51单片机数码管的编程时,我们需要先定义相应的引脚和端口。引脚定义是通过给出引脚在芯片内部的位置来实现的。在51单片机中,我们一般使用P0口来控制数码管的显示,而P2口用于设置显示的值。我们可以通过设置P0口和P2口的相应引脚为高电平或低电平来控制数码管的亮灭。

51单片机数码管编程的实现步骤:

  1. 首先,我们需要在程序中定义数码管段码和显示数值之间的对应关系。通过对数码管每个段的控制,我们可以实现不同数字、字母或符号的显示。例如,通过设置数码管的特定段为高电平,可以在该段显示相应的数字。
  2. 然后,我们需要在程序中设置数码管的显示值。通过设置P2口的相应引脚为高电平或低电平,可以控制显示数码管的值。我们可以使用指令来设置P2口的相应引脚,从而确定数码管需要显示的值。
  3. 接下来,我们需要设置数码管的动态显示。数码管的动态显示是通过快速地切换不同位数码管的显示来实现的。我们可以通过定时器中断来控制数码管的动态显示,使其显示出连续变化的数字。
  4. 最后,我们需要在主程序中进行相应的配置和控制。在主程序中,我们可以配置定时器和中断,并通过设置相应的标志位来控制数码管的动态显示。同时,我们可以通过循环来反复执行数码管的更新显示操作,从而实现连续的动态显示效果。

通过以上步骤的实现,我们就可以完成51单片机数码管的编程。通过控制引脚的电平,设置数码管的段码和显示值,以及实现动态显示,我们可以实现对不同数字、字母或符号的显示。这为我们设计各种实用、有趣的电子项目提供了基础。

总结:

在嵌入式系统开发中,掌握单片机的编程是非常重要的。数码管作为一种常见的显示器件,在各种电子设备中有着广泛的应用。通过掌握51单片机数码管的编程,我们可以实现对数字的显示和动态显示,为我们的电子项目增添更多的功能和乐趣。

通过本文的介绍,大家已经对51单片机数码管编程有了初步的了解。希望本文能够对大家在嵌入式系统开发中学习和应用数码管编程提供一些帮助。谢谢大家的阅读!

热门文章