2018-09-28 16:09:17 mylovewanzi 阅读数 4142
  • 单片机控制第一个外设-LED-第1季第6部分

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

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

单片机实验----跑马灯


实验效果:

  • 8只LED灯轮流点亮,从左到右,再从右到左,不断循环。

知识点:

  • RL指令
  • RR指令
  • 高128位单元

代码:

		ORG 	0000H			;主程序
MAIN: 	MOV 	A,#0FEH			;acc初始化,11111110B
LOOP: 	MOV 	P1,A			;将acc的数据传送到P1口
		LCALL 	DELAY 			;调用延迟子程序
		RL 		A				;将acc中的数据左右一位
		LJMP 	LOOP			;回到LOOP标记处,点亮下一盏灯
DELAY: 	MOV 	R1,#200			;延时子程序
D1:    	MOV 	R2,#150
D2:    	DJNZ 	R2,D2
		DJNZ 	R1,D1
		RET						;返回主程序
		END

我们知道控制P1口的数值可以使得LED灯亮或者灭。
那怎么改变P1口的数值呢?
我们可以通过RL指令。

原理:
我们将11111110B传给P1口,再用RL指令将11111110B左移,改变11111110B中0的位置,来达到改变P1口8位的数值,从而控制LED的亮灭。

  1. RL指令
    格式:RL A
    功能:将acc中的数据循环左移一位,以形成新的数据

  2. RL指令
    格式:RR A
    功能:同上,循环左右移

  3. 高128单元
    如图:即80H~FFH
    内部数据存储器

高128单元,称为特殊功能寄存器区,也称专用功能寄存器区。这个区包含22个专用寄存器。
这个区主要存放相应功能部件的控制命令、状态或数据。

特殊功能寄存器:
特殊功能寄存器

这些专用寄存器分为3类:

累加器A(或acc)

acc是一个8位寄存器,常用A表示。
acc是一个很重要的寄存器,运算的时候经常会用到。
一方面它可以做加法器,一方面也可以作为寄存器。

累加器的常用功能:

  1. 存放操作数和运算后的结果
  2. 内部与外部RAM数据传送的中转站

一般来说,A代表累加器,而ACC代表累加器的地址。

程序状态字(PSW)寄存器

PSW是一个8位寄存器,用于存放执行指令后的有关状态信息。

如图:
psw寄存器1

psw寄存器2

  1. 进位标志位CY或C(PSW.7)
    标志加法与减法运算中的进位与借位状态。
    加法中:若有进位则CY=1,否则为0。
    减法中:若有借位则CY=1,否则为0。
    它是最常用到的标志,通常在位传送、位与、位或等操作中使用。

  2. 辅助进位标志位AC(PSW.6)
    用在加或减运算中,表示低四位有没有向高四位进位或借位。
    若有则AC=1,否则为0。

  3. 寄存器选择位RS1和RS0(PSW.4和PSW.3)
    用户可以通过改变他们的值,来选择当前工作寄存器区的组别。

如图:
当前工作寄存器选择表

数据指针(DPTR)
是一个16位的寄存器,本质是两个8位寄存器组合而成。
DPTR比较灵活:

  1. 作为16位寄存器使用,此时可以对64k的外部数据存储器和I/O地址进行寻址。
  2. 作为两个8位寄存器使用,此时DPH为DPTR的高字节,DPL为DPTR的低字节。

时间:2018年9月28日16:08:36


-END-

2019-01-08 10:21:16 chen18221987993 阅读数 1723
  • 单片机控制第一个外设-LED-第1季第6部分

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

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

个人网站:https://chenqi.autmake.com/

接触单片机的第一个实验就是跑马灯实验,虽然实验并不难,但开始却并不容易,跑马灯实验对于老司机来说简直小菜一碟。可这对于一个不懂硬件的新手来说,真的不容易。那段时间经常看STM32中文参考手册_V10,也看了Cortex-M3权威指南。慢慢的明白了其中的原理,也知道了为什么要配置成上拉、下拉、推挽输出、复用推挽输出。

跑马灯实验大致可以分为三个步骤:

1. LED初始化

LED初始化包括时钟初始化和引脚初始化。每一个外设都有其对应的时钟,所以在使用外设之前都要先开启外设的时钟。

引脚初始化(端口初始化),本实验是要通过引脚输出高低电平来控制LED的亮灭。端口初始化主要是配置:输出引脚、输出模式、输出速率。

初始化代码如下:

/*本次跑马灯实验主要用到PB6~PB9几个端口*/
#include "LED.h"

void LED_Init(void)  //自定义Led灯初始化函数
{  
    GPIO_InitTypeDef  GPIO_InitStructure;  
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE); /*使能LED灯使用的GPIO时钟*/     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //以上为配置GPIO
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB 
}

附上头文件:

/*头文件中主要是一些宏定义和位带操作*/
#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

#define LED1_ON GPIO_SetBits(GPIOB, GPIO_Pin_6)
#define LED1_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_6)
#define LED2_ON GPIO_SetBits(GPIOB, GPIO_Pin_7)
#define LED2_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_7)
#define LED3_ON GPIO_SetBits(GPIOB, GPIO_Pin_8)
#define LED3_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_8)
#define LED4_ON GPIO_SetBits(GPIOB, GPIO_Pin_9)
#define LED4_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_9)
	 
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define LED1  PBout(6)
#define LED2  PBout(7)
#define LED3  PBout(8)
#define LED4  PBout(9)

void LED_Init(void);

#endif

2.延时函数的编写

跑马灯实验中需要用到延时函数,这个网上有很多例子。下面给出一个比较常用且精准的延时函数。有兴趣的也可以自己去编写属于自己的延时函数。这个函数比较常用,在后面的实验中也会经常用到。

源文件:

#include "delay.h"

void delay_us(u32 nus)
{
	u32 temp;
	SysTick->LOAD = 9*nus;
	SysTick->VAL=0X00;//清空计数器
	SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
	do
	{
		temp=SysTick->CTRL;//读取当前倒计数值
	}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

void delay_ms(u16 nms)
{
	u32 temp;
	SysTick->LOAD = 9000*nms;
	SysTick->VAL=0X00;//清空计数器
	SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
	do
	{
		temp=SysTick->CTRL;//读取当前倒计数值
	}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

头文件:

#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f10x.h"

void delay_us(u32 nus);
void delay_ms(u16 nms);

#endif

3.主函数编写

主函数就比较简单了,先调用LED的初始化函数,然后依次点亮LED。

/*引用头文件是为了调用其中定义的函数*/
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"

int main(void)
{   
    LED_Init(); 
    while(1)
    {     
        LED1 = 1;
        delay_ms(200);
        LED1 = 0;
        delay_ms(200);
        LED2 = 1;
        delay_ms(200);
        LED2 = 0;
        delay_ms(200);
        LED3 = 1;
        delay_ms(200);
        LED3 = 0;
        delay_ms(200);
        LED4 = 1;
        delay_ms(200);
        LED4 = 0;
        delay_ms(200);
    }   
}

至此,跑马灯实验就结束了。新手切不可完全照搬,要根据自己的原理图来做相应的修改,加入自己的思考,才会真正成为自己的东西。

完整工程下载链接:https://pan.baidu.com/s/109sOF0eroGE0bHeTTM1Fww

2016-08-26 10:45:17 u012313335 阅读数 1552
  • 单片机控制第一个外设-LED-第1季第6部分

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

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

       单片机的跑马灯实验就如同 C 语言的"Hello World!"程序一样,几乎所有单片机试验课程都会介绍到跑马灯试验,简单的跑马灯只需选择P0 - P3口其中一个和8个LED灯连接即可。自动变速跑马灯通过定时器中断的控制能准确控制跑马灯频率。

       对于定时器的中断的工作方式,我们可以建立两个全局的标记,一个在中断里置这个标记,然后就退出。在主程序里检查到这个标记之后,就运行相关的程序。另一个用来控制跑马灯速率,当跑马灯跑完8个LED后,对速率标记减一,使速率加快。


#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
bit delay = 0;
uchar speed = 10;

/*******************************************************************************
* 函数名         : TimerConfiguration()
* 函数功能	 : 配置定时器值
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void TimerConfiguration()
{
    TMOD = 0x01; 	 //选择工作方式1
    TH0 = 0x28; 	 //设置初始值
    TL0 = 0x69;
    EA = 1;			 //打开总中断
    ET0 = 1;		 //打开定时器0中断
    TR0 = 1;		 //启动定时器0
}

void main()
{
	uchar mark = 0;		//标记跑马灯是否跑完
	P0 = 0x01;
	TimerConfiguration();
	while(1)
	{
		if(delay)
		{
			delay = 0;
			P0 = _crol_(P0,1);
			mark++;
			if(mark == 8)
			{
				mark = 0;
				speed--;
				if(speed == 0)
					speed = 10;		//每循环显示一次,就调快一次溢出速度
			}
		}
	}	
}

/*******************************************************************************
* 函数名         : Timer0()
* 函数功能       : 定时器0中断函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void Timer0() interrupt 1
{
	uchar t;
	t++;
	if(t == speed)
	{
		t = 0;
		delay = 1;
	}
}


2017-06-02 00:17:56 perfectguyipeng 阅读数 590
  • 单片机控制第一个外设-LED-第1季第6部分

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

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

      今天根据网上的教程实现了STM32F1系列单片机的跑马灯实验,首先主要分为三个步骤:

(1)使能IO口时钟,调用函数RCC_APB2PeriphClockCmd();不同的IO口,调用的使能时钟不一样

(2)初始化IO口模式。调用函数GPIO_Init();

(3)操作IO口,输出高低电平。GPIO_SetBits();GPIO_ResetBits();

         新建一个样板工程,在工程添加文件夹HAREWARE,并在文件夹添加LED(名字自取)的.c和.h文件,按照上述的步骤,依次添加步骤。

      LED.h:

#ifndef __LED_H_
#define __LED_H_

void LED_Init(void) ;   //初始化


#endif

      LED.c:

#include "LED.h"
#include "stm32f10x.h"

void LED_Init(void) 
{
	GPIO_InitTypeDef  GPIO_InitStr ;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);   //GPIOD
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //GPIOA
	
	GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_PP ;  //推挽输出
	GPIO_InitStr.GPIO_Pin = GPIO_Pin_2 ;   
	GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init(GPIOD,&GPIO_InitStr) ;
	GPIO_SetBits(GPIOD,GPIO_Pin_2) ;  //设置高电平
	
	GPIO_InitStr.GPIO_Mode = GPIO_Mode_Out_PP ;  //推挽输出
	GPIO_InitStr.GPIO_Pin = GPIO_Pin_8 ;   
	GPIO_InitStr.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init(GPIOA,&GPIO_InitStr) ;
	GPIO_SetBits(GPIOA,GPIO_Pin_8) ;  //设置高电平

	
}
      在main函数中,执行操作,对LED设置高低电平,让其闪烁,并且加上延时函数:

#include "stm32f10x.h"
#include "LED.h"
#include "delay.h"


int main(void)
{	
   delay_init();
	 LED_Init();
	 
	 while(1)
	 {
		 GPIO_SetBits(GPIOD,GPIO_Pin_2) ;   //高电平  熄灭
		 GPIO_SetBits(GPIOA,GPIO_Pin_8) ;
		 delay_ms(500) ;
		 
		 GPIO_ResetBits(GPIOD,GPIO_Pin_2) ;  //低电平 点亮
		 GPIO_ResetBits(GPIOA,GPIO_Pin_8) ;
		 delay_ms(500) ;	 
		 
	 }
	 
}
        就这样,基于STM32F1x系列单片机的简单跑马灯实验便做好了,接下来继续学习STM32F1x系列其他知识,加油!




2019-10-04 18:02:32 baidu_24694009 阅读数 23
  • 单片机控制第一个外设-LED-第1季第6部分

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

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

手把手编写跑马灯实验

库函数版

实验步骤

在这里插入图片描述

  • 使能相应IO口时钟
    查看时钟使能函数定义
    在这里插入图片描述
    发现该函数实际是对寄存器-APB2ENR进行操作

    入口参数判断IS_RCC_APB2_PERIPH是否有效在这里插入图片描述
    使能谁,复制谁 在这里插入图片描述
    判断IS_FUNCTIONAL_STATE
    在这里插入图片描述
    判断是否是使能状态
    在这里插入图片描述

  • 初始化IO口模式

  • 操作IO口,输出高低电平

1.工程模板下新建硬件文件夹,.c .h文件,并添加进project

在这里插入图片描述
在这里插入图片描述
在头文件(.h)中对函数进行声明
在这里插入图片描述
在源文件(.c)中对函数进行具体定义

  • 使能相应IO口时钟
    在这里插入图片描述
    也可写作
    在这里插入图片描述

  • 初始化IO口模式,调用函数GPIO_Init()
    在这里插入图片描述
    在这里插入图片描述
    GPIO_TypeDef* GPIOx → GPIOB
    GPIO_InitTypeDef* GPIO_InitStruct → GPIO_InitStructure
    在这里插入图片描述
    定义GPIO_InitStructure过程:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 操作IO口,输出高低电平
    GPIO_SetBits
    GPIO_ResetBits
    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    查找自己使用开发板原理图查看LED对应引脚
    本文使用正点原子精英STM32F103,LED0对应PB5,LED1对应PE5
    在这里插入图片描述
    点亮LED:
    GPIO_SetBits(GPIOB,GPIO_Pin_5);
    GPIO_SetBits(GPIOE,GPIO_Pin_5);
    熄灭LED:
    GPIO_ResetBits(GPIOB,GPIO_Pin_5);
    GPIO_ResetBits(GPIOE,GPIO_Pin_5);

主程序文件(main.c)编写

  1. 程序框架搭建
    在这里插入图片描述
  2. 操作IO口输出高低电平
    在这里插入图片描述
  3. 加入延迟效果
    在这里插入图片描述
  4. 烧录程序
  5. 观察现象

寄存器版

实验步骤

在这里插入图片描述

  1. 使能IO口时钟。配置寄存器RCC_APB2ENR
    新建工程模板
    在stm32f10x.h中查看RCC写法
    在这里插入图片描述
    在这里插入图片描述
    添加时钟定义寄存器及所引用到的头文件
    在这里插入图片描述
    在中文参考手册中查看使能IO口时钟需要控制寄存器中哪些位
    在这里插入图片描述
    在这里插入图片描述
    只需操作第3位及第6位
    操作位3使能GPIOB
    在这里插入图片描述
    或运算:A|=B; 即A=A|B;
    RCC->APB2ENR|=1<<3; 即RCC->APB2ENR或等于1左移三位
    在这里插入图片描述
    如图所示,其他位或0则不影响原有数值,第三位或1计算,不论原值0/1第三位都会变为1
    同理,操作位6使能GPIOE
    在这里插入图片描述
  2. 初始化IO口模式。配置寄存器GPIOx_CRH/CRL
    LED0对应PB5,LED1对应PE5
    操作GPIO寄存器
    在中文参考手册中查看端口配置寄存器
    CRL控制0-7位,CRH控制8-15位,本实验操作第5位即控制CRL
    在这里插入图片描述
    即对20-23进行赋值,赋值前先使用与运算(&)将对应位数清零
    在这里插入图片描述
    该写法为16进制写法,与二进制进行转换
    FF0FFFFF(16进制)>11111111000011111111111111111111(2进制)
    (0x开头是十六进制的标识符,也可写作FF0FFFFFH)
    在这里插入图片描述
    清零后用或运算(|)对20-23赋值0011(2进制)>3(16进制)
    在这里插入图片描述
  3. 操作IO口,输出高低电平。配置寄存器GPIOx_ODR或者BSRR/BRR
    在这里插入图片描述
    第5位输出高电平在这里插入图片描述
    编写主函数
    在这里插入图片描述
    添加延时及输出低电平
    在这里插入图片描述
    ~非运算第5位赋值1后取反为0(多位数复杂操作时可先非后与)
    在这里插入图片描述
没有更多推荐了,返回首页