单片机
2013-06-09 22:18:00 a379039233 阅读数 4778
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

      单片机就是一个小的计算机,不过他没有计算机那么好,方便的输入输出设备,计算机的输入设备就是鼠标,键盘等,方便的很,输出设备就是显示器,将输出非常清晰的显示在屏幕上。但是单片机的输入输出都是他的引脚,需要通过编程控制。

       单片机和PC机相同的地方就是都有CPU(我把单片机的微控制器核也叫CPU),内存(单片机的ROM,RAM,FLASH等),时钟系统,中断系统,定时器等等。

      一, 单片机最小系统就是单片机能够运行起来的必要条件:

   1.电源 2.晶振 3.复位电路  没有电源就没有能源,就不能工作;没有晶振,就没有时钟电路,就没有节拍,指令就不能按一定的步调运行;没有复位电路,单片机就很不可靠,会出现“死机”、“程序走飞(PC)”等现象。
   
   二,一些重要概念
    1. 我们对单片机编程不过就是设置单片机内部的寄存器和端口引脚以便输出高低电平控制其他(连接在单片机上)器件而已。
    2. 编程中最重要的是1:配置时钟,2:配置IO口,3:配置复位方式,看门狗设置等等
       次要的是:中断(外部,定时器,串口),串口,ADC,XRAM读写,内部FLASH等。   
    3. 1个机器周期 =12个时钟周期(晶振的振荡周期)   
    4. while(1);让单片机一直工作,等待中断!防止程序跑飞等。
    5. 51单片机共111条汇编指令,
7种寻址方式:
1.立即寻址 MOV A,#01H
2.直接寻址 MOV A,20H
3.寄存器寻址 MOV A,R3(A,B,Cy,DPTR)

4.寄存器间接寻址 MOVA,@R0  R1
5.变址寻址 MOVC  A, @A+DPTR
6.相对寻址 SJMP   rel; (PC)←(PC) + 2(指令长度) +  rel
7.位寻址 位寻址是直接寻址方式的一种,其特点是对8位二进制数中的某一位的地址进行操作。
MOV 00h,C,MOV  20H.0, C  ,PSW.6
 
     6. XRAM(分内外)读写 
      1> XBYTE[address]=data   写数据
         data=XBYTE[address]   读数据;
   2>char xdata *mydat;
      ......
      mydat=(char xdata*)0x0030;
      *mydat=31;
   3>汇编方式
	mov dptr,#1000h
	mov a,#55h
	movx @dptr,a
      7.  读端口信号是必须先向端口写“1”,然后再读,这就是单片机口信号的准双向的含义。切记!
      8.  模拟输入或数字I/O,推挽(强)或漏极开路输出(IO,inout)

 
9. 一些寄存器默认设置即可,配置了可能会有警告。usb clock.clksel=1  10. Keil C 里面Lib库文件的生成与调用,可以自己做lib。
11. ram高128位只能间接寻址。idata,一些人可能没有用到idata,发现data不够用。
12 1s=1000ms=1000000us=1000000000ns.
13.
x M晶振定时 y ms: TH1 = (65536 - (x/12)*y*1000) / 256;     TL1 = (65536 - (x/12)*y*1000) % 256;16位的哦,亲!
假设C8051F020单片机的晶振是22114800Hz,测每秒计22114800个数 经过12分频后,每秒计22114800÷12=1842900个数,如果设置计数器初值是 0xfe90(即十进制65165),则需要计的数的个数为65535-65165=360,那么定时器的 时间为(360÷1842900)(S)≈0.195ms,即0.2ms。
#define uchar unsigned char
#define uint  unsigned int
#define ulong unsigned long #define bool  bit
 
#include<C8051F330.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long //引脚定义
sbit In1= P0^3; sbit In2= P0^7; sbit In3= P1^3; sbit In4= P1^7; sbit Out1= P0^3; sbit Out2= P0^7; sbit Out3= P1^3; sbit Out4= P1^7;
//----------------------------------------------------------------------------- //功能:延时 //入口参数:yc //出口参数:无 //-----------------------------------------------------------------------------
void delay(uint time)
{
  while(--time);
}
//----------------------------------------------------------------------------- //功能:单片机C8051F330初始化 //入口参数:无 //出口参数:无 //-----------------------------------------------------------------------------
void Mcu_Init(void) { 
  PCA0MD&=~0x40;                 //禁止内部看门狗  
  OSCICN = 0x83;                 //内部振荡控制寄存器,使能H-F,八分频  
OSCICL = 0x00;                 //期望输出频率也是24.5MHz
  CLKSEL = 0x00;                  //系统时钟取自内部高频振荡器  
RSTSRC = 0x04;                 //检测到时钟丢失时允许系统复位
}
 
 
//----------------------------------------------------------------------------- //功能:MCU I/O口配置 //入口参数:无 //出口参数:无 //-----------------------------------------------------------------------------
 
void PORT_Init (void) {    
P0MDOUT  = 0x88;                         //P0.3,P0.7推挽输出   
P1MDOUT  = 0x88;                  //P1.3,P1.7推挽输出   
XBR0     = 0x00;  
  XBR1     = 0x40;                  //使能交叉开关和弱上拉 }
//----------------------------------------------------------------------------- // 功能:所有设备初始化 //----------------------------------------------------------------------------- // 入口参数:无 // 出口参数:无 //-----------------------------------------------------------------------------
 
void Init_Device (void) {   
Mcu_Init();   
PORT_Init();
} void main() {
     Init_Device();     
delay(10);          
     while(1){            }
 
}
2012-10-11 09:37:36 talentluke 阅读数 102
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

    3997 人正在学习 去看看 朱有鹏
把单片机看成是一个箱子,引脚就是外面的管子。

通过引脚给单片机发送信号,叫做输入啊,同理,单片机给外界信号,就要靠引脚输出啊,有些引脚既可以输出,也可以输入,有些引脚只能输入或只能输出。

输入就是键盘输入等,要你动手,输出就是你看见的,不要动手 。

输入就是把外部的信号给单片机;输出就是把单片机的信号给外部 。

输入---把你自己的东西放进盒子(单片机)。
输出---从盒子里(单片机)取出你要的东西 。
2014-11-09 20:00:59 lixiangminghate 阅读数 2412
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

传统51MCU的定时器没有时钟输出功能,此处使用的是增强型51MCU,型号stc12c5a60。

寄存器功能介绍之类的就省略了,数据手册上写的足够明了。由于protues不支持stc增强型MCU,只能烧写到芯片中,再用示波器验证。这点对于个人用户而言还是挺不方便的

真心希望哪天stc能提供protues的仿真元件。

STC提供了3路时钟输出,可以运行在1T/12T(即,对系统时钟12分频)模式下,1T模式感觉都可以取代其PCA的高速输出模式。

下面罗列代码,T0工作在1T模式/T1工作在12T模式。

#include "STC/STC12C5A.H"

#define MakeByte(target, Hi,Lo) \
do{ \
	target |= (((Hi)<<4)|(Lo)); \	
}while(0); \

#define SetTH(n,val) \
do{ \
	TH##n = val; \
}while(0); \

#define SetTL(n,val)  \
do{ \
	TL##n = val; \
}while(0); \

#define StartTn(n) \
do{ \
	TR##n = 0x01; \
}while(0);	\

#define Enable1TMode(n) \
do{ \
	AUXR |= n; \	
}while(0); \

#define EnableClkOut(n) \
do{ \
	WAKE_CLKO |= n; \
}while(0); \

int main()
{
	//T1 T0工作在定时器输出时,只能工作在模式2
	MakeByte(TMOD,0x02,0x02);
	//允许T1(P3.5)脚输出溢出脉冲
	EnableClkOut(T1CLKOEN);
	//T1 12分频,输出时钟频率 = Fosc/(12*(256-TH1)*2)
	SetTL(1,0x38);
	SetTH(1,0x38);
	//开启1T模式
	Enable1TMode(T0x12);
	//允许T0(P3.4)脚输出溢出脉冲
	EnableClkOut(T0CLKOEN);
	//T0 1分频 输出时钟频率 = Fosc/((256-TH1)*2)
	SetTL(0,0xF4);
	SetTH(0,0xF4);

	StartTn(1);
	StartTn(0)
	while(1);
}
感觉时钟输出功能就是把本来应该在中断中翻转引脚的功能,拿到MCU内部由片上系统实现了,所以输出的时钟频率被减半了。(2次时钟中断正好完成一个波形周期)
鉴于示波器比较简陋,就不上图了

2016-04-25 10:25:35 ludaoyi88 阅读数 2190
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

前段时间不小心把8位的并行数据口刚好倒序反接了,为了不改硬件下,在程序里将得到的一字节数的8位2机制进行倒序处理,处理后一字节返回。经过对代码的不断简练,下面附上倒序处理的算法。个人觉得有时比较有用,网友们有其它更好算法也可以给以借鉴!


unsigned char Convert_Byte(unsigned char Data) 
{
char i;
unsigned char Data1;
Data1 = Data;
Data = 0x00;

for(i = 0 ; i<(sizeof(char)*8/2) ; i++)
{
Data = Data | (Data1&(0X80>>i))>>(7-i*2);
Data = Data | (Data1&(0X01<<i))<<(7-i*2);
}

return  Data;

}

2019-01-06 13:41:14 weixin_44017446 阅读数 4015
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

PWM输出

学期快结束了,51单片机的学习也差不多告一段落,也快要转入新的学习阶段,寒假找个时间看看32,小白哈哈哈,下面是我学习51定时器弄出来的小东西,一个PWM的输出。还请大神指点。

刚开始觉得PWM输出应该不难,很容易做的,但是后面越像越多,就感觉其实做不来不难,做精确才难,刚开始想到的用一个定时器做,也就是在中断里面计数,来个中断计数加一,判断到自己想要的值就改变电平,这样做思路简单,但有一个坏处,就是有个0.14ms的误差无法消除(可能是我太菜,没找到解决方法),后来就想到用两个定时器做了,定时器0,用来改变周期,定时器1,用来改变占空比,当定时器0来一个中断时,PWM=1,并开启定时器1,定时器1来一个中断时,PWM=0,关闭定时器,至于为什么要关闭定时器1,是因为定时器1的初值比较小,可能在定时器0还没发生中断的时候,就发生几次中断了,所以会影响PWM输出,还有发生中断的时候,有一些时间,和运行的时候有些静态误差,所以在初值哪儿微调。
废话少说,直接上代码。
延时函数

#ifndef __DELAY_H
#define __DELAY_H
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int 
void delay_ms(uint i);

#endif

#include "delay.h"
void delay_ms(uint i)
{
	uchar n;
 	while(i--)
	for(n=0;n<120;n++)
	;

}

下面直接主函数了

#include "sys.h"				//自己写的一个头文件
#include "delay.h"

unsigned int tim0_I; //占空时间
unsigned int tim0_T;		 //周期
uchar Temp_TH0,Temp_TL0;
uchar Temp_TH1,Temp_TL1;

sbit PWM=P1^0;	//输出引脚
sbit key0=P3^2;
sbit key1=P3^3;
sbit key2=P2^0;
sbit key3=P2^1;
void INT_Init_KEY();
void key2_Init();
void key3_Init();
void TIM0_Init_PWM();	//初始化

//sbit LED=P1^0;
void main()
{
//	uchar i;

	tim0_I=600;
	tim0_T=1000;
	PWM=0;
	TIM0_Init_PWM();
	
	INT_Init_KEY();
	while(1)
	{
		key2_Init();
		key3_Init();
		delay_ms(10);	
	}
}


void TIM0_Init_PWM()		 //定时器0初始化
{
	TMOD=0x11;				//方式1:为16位定时/计数器
	TH0=(uint)(65535-tim0_T)/256;		//取低8位	//设置初始值10us
	TL0=(uint)(65535-tim0_T)%256;		 //取低8位
	TH1=(uint)(65535-tim0_I)/256;
	TL1=(uint)(65535-tim0_I)%256;
	TR1=1;
	TR0=1;
	ET1=1;		
	TR0=1;					 //打开定时器0
	ET0=1;					 //打开外部中断
	EA=1;					 //打开总中断

}

void tim0_Int_PWM()	interrupt 1 //设定周期
{
//	TR0=0;   				 //设置定时器初值期间,关闭定时器


  	TH0=(uint)(65535-tim0_T+28)/256;		 //定时器赋值
  	TL0=(uint)(65535-tim0_T+28)%256;		//加28是为了消除静态误差,还有中断反应时间,下面加30也一样
// 	TR0=1;
	PWM=1;
	TR1=1;
}
void tim1_Int_PWM()	interrupt 3 			//占空比
{
  				 
  	TH1=(uint)(65535-tim0_I+30)/256;		 //定时器赋值
  	TL1=(uint)(65535-tim0_I+30)%256;
	PWM=0;
	TR1=0;//需要把定时器1关了,这样它就不会一直跳,让它一个周期内只跳一次
}
void key2_Init()	 //周期加1
{
	if(key2==0)
	{
	delay_ms(100);
	if(key2==0)
	{
		tim0_T+=1000;
	}
	}
}
void key3_Init()	 //周期减1
{
	if(key3==0)
	{
	delay_ms(100);
	if(key3==0)
	{
		if(tim0_T>0)
			tim0_T-=1000;
	}
	}
}
void INT_Init_KEY()	   //外部中断初始化
{
	 EA=1;
	 EX0=1;
	 EX1=1;
	 IT0=1;
	 IT1=1;
	 PX0=1;
	 PX1=1;
}

void INT0_KEY0() interrupt 0	  //外部中断0 服务程序//占空时间加1
{
	delay_ms(10);
	if(key0==0)
	{
		if(tim0_I<tim0_T)
		tim0_I+=10;		
	}
	while(!key0) ;
}
void INT1_KEY1() interrupt 2	  //外部中断1 服务程序//占空时间减1
{
	delay_ms(10);
	if(key1==0)
	{	
		if(tim0_I>0)
		tim0_I-=10;
		
			
	}
	while(!key1) ;
}

我就一小白,不足之处,还请指出。

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