1 8051CPU
8051是一种8位元的单芯片微控制器,属于MCS-51单芯片的一种,由英特尔(Intel)公司于1981年制造。Intel公司将MCS51的核心技术授权给了很多其它公司,所以有很多公司在做以8051为核心的单片机,如Atmel、飞利浦、深联华等公司,相继开发了功能更多、更强大的兼容产品。
总体架构
CPU主要由以下几个部分组成:
(1)运算器: 运算器由算术/逻辑运算单元ALU、累加器ACC、寄存器B、暂存寄存器、程序状态字寄存器PSW组成。
(2)控制器: 控制器由指令寄存器IR、指令译码及控制逻辑电路组成。
(3)其他寄存器: 程序计数器PC、数据指针DPTR、堆栈指针SP、工作寄存器R0~R7
内存映射
SRAM映射到地址范围为0x0000到(SRAMSIZE-1)
XREG区域映射到1KB地址范围(0x6000-0x63FF)中。这些寄存器是附加寄存器,有效地扩展了SFR寄存器空间。一些外围寄存器和大多数无线电控制和数据寄存器都映射在这里。
SFR寄存器映射到地址范围(0x7080-0x70FF)闪存信息页(2KB)陕射到地址范围(0x7800-0x7FFF)中。这是一个只读区域,包含有关设备的各种信息。
SFR寄存器地址总览
2 基础实验
2.1 流水灯
实验目的
相关寄存器
下面我们以 P1.0 控制的 LED1 为例,操作 P1.0 时我们需要掌握相关寄存器的作用和配置方法。
下面我们以 P1.0 控制的 LED1 为例,操作 P1.0 时我们需要掌握相关寄存 器的作用和配置方法。
/****************************************************************************
* 文 件 名: main.c
* 作 者:
* 网 站:
* 修 订:
* 版 本: 1.0
* 描 述: 操作IO口控制4盏LED灯的全亮和全灭、闪烁、流水灯
****************************************************************************/
#include <ioCC2541.h>#define uchar unsigned char
#define uint unsigned int #define LED1 P1_0 //定义P1.0口为LED1控制端
#define LED2 P1_1 //定义P1.1口为LED2控制端
#define LED3 P0_4 //定义P0.4口为LED3控制端/****************************************************************************
* 名 称: Delay_ms()
* 功 能: 以毫秒为单位延时,系统时钟不配置时默认为16M(用示波器测量相当精确)
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMs(uint len)
{ while(len--)for (int i=0; i<535; i++);
}/****************************************************************************
* 名 称: LedOnOrOff()
* 功 能: 点亮或熄灭所有LED灯
* 入口参数: mode为1时LED灯亮 mode为0时LED灯灭, 共阴极
* 出口参数: 无
****************************************************************************/
void LedOnOff(uchar mode)
{LED1 = mode;LED2 = mode;LED3 = mode;
}/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED灯相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{P1DIR |= 0x03; //P1.0、P1.1定义为输出P0DIR |= 0x10; //P0.4定义为输出LedOnOff(0); //使所有LED灯默认为熄灭状态
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{uchar i;InitLed(); //设置LED灯相关IO口while(1) //死循环{ LED1 = !LED1; //流水灯,初始化时LED为熄灭执行后则点亮DelayMs(200); LED2 = !LED2; DelayMs(200); LED3 = !LED3; DelayMs(200); for (i=0; i<2; i++) //所有灯闪烁2次{LedOnOff(0); //关闭所有LED灯DelayMs(200);LedOnOff(1); //打开所有LED灯DelayMs(200);}LedOnOff(0); //使所有LED灯熄灭状态DelayMs(200);LedOnOff(1); DelayMs(500);LedOnOff(0); //使所有LED灯熄灭状态DelayMs(200);}
}
2.2 按键控制 LED 跑马灯
/****************************************************************************
* 文 件 名: main.c
* 作 者:
* 网 站:
* 修 订:
* 版 本: 1.0
* 描 述: 按下按键S1控制LED1.LED2.LED3实现跑马灯效果
****************************************************************************/
#include <ioCC2540.h>#define uchar unsigned char
#define uint unsigned int #define LED1 P1_0 // 定义P1.0口为LED1控制端
#define LED2 P1_1 // 定义P1.1口为LED2控制端
#define LED3 P0_4 // 定义P0.4口为LED3控制端
#define KEY1 P0_1 // 定义P0.1口为S1控制端
#define ON 1
#define OFF 0/****************************************************************************
* 名 称: DelayMS()
* 功 能: 以毫秒为单位延时,系统时钟不配置时默认为16M(用示波器测量相当精确)
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint len)
{ while(len--)for (int i=0; i<535; i++);
}/****************************************************************************
* 名 称: LedOnOrOff()
* 功 能: 点亮或熄灭所有LED灯
* 入口参数: mode为1时LED灯亮 mode为0时LED灯灭
* 出口参数: 无
****************************************************************************/
void LedOnOrOff(uchar mode)
{LED1 = mode;LED2 = mode;LED3 = mode;
}/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{P1DIR |= 0x03; // P1.0、P1.1定义为输出P0DIR |= 0x10; // P0.4定义为输出LedOnOrOff(0); // 使所有LED灯默认为熄灭状态
}/****************************************************************************
* 名 称: InitKey()
* 功 能: 设置按键相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitKey(void)
{P0SEL &= ~0x02; //设置P0.1为普通IO口 P0DIR &= ~0x02; //按键接在P0.1口上,设P0.1为输入模式 P0INP &= ~0x02; //打开P0.1上拉电阻
}/****************************************************************************
* 名 称: KeyScan()
* 功 能: 读取按键状态
* 入口参数: 无
* 出口参数: 0为抬起 1为按键按下
****************************************************************************/
uchar KeyScan(void)
{if (KEY1 == 0){DelayMS(10); //延时10MS去抖if (KEY1 == 0){while(!KEY1); //松手检测return 1; //有按键按下}}return 0; //无按键按下
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{InitLed(); //设置LED灯相应的IO口InitKey(); //设置按键S1相应的IO口while(1){DelayMS(2);if (KeyScan()) //扫描按键当前状态,按下按钮 松开 后执行{LED1 = ON; //点亮LED1 DelayMS(200); LED1 = OFF; //熄灭LED1 LED2 = ON; DelayMS(200); LED2 = OFF; LED3 = ON; DelayMS(200); LED3 = OFF; }}
}
2.3 外部中断
原理同上
/****************************************************************************
* 文 件 名: main.c
* 描 述: 通过按键S1产生外部中断改变LED1状态
****************************************************************************/
#include <ioCC2541.h>#define uchar unsigned char
#define uint unsigned int#define LED1 P1_0 // P1.0口控制LED1
#define KEY1 P0_1 // P0.1口控制S1/****************************************************************************
* 名 称: DelayMS()
* 功 能: 以毫秒为单位延时,系统时钟不配置时默认为16M(用示波器测量相当精确)
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint len)
{ while(len--)for (int i=0; i<535; i++);
}/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED灯相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{P1DIR |= 0x01; //P1.0定义为输出口LED1 = 0; //LED1灯灭
}/****************************************************************************
* 名 称: InitKey()
* 功 能: 设置KEY相应的IO口,采用中断方式
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitKey()
{P0IEN |= 0x02; // P0.1 设置为中断方式 1:中断使能PICTL |= 0x02; //下降沿触发 IEN1 |= 0x20; //允许P0口中断; P0IFG = 0x00; //初始化中断标志位EA = 1; //打开总中断
}/****************************************************************************
* 名 称: P0_ISR(void) 中断处理函数
* 描 述: #pragma vector = 中断向量,紧接着是中断处理程序
****************************************************************************/
#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void)
{ DelayMS(10); //延时去抖LED1 = ~LED1; //改变LED1状态P0IFG = 0; //清中断标志 P0IF = 0; //清中断标志
} /****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{InitLed(); //设置LED灯相应的IO口InitKey(); //设置S1相应的IO口while(1){}
}
2.4 定时器 T1-查询方式
定时器T1的时钟频率为32MHz / 128 = 250kHz。
在这个配置下,当T1计数器溢出时,中断标志位IRCON会被置位。通过查询IRCON的值是否大于0,代码检测是否发生了定时器T1的中断。
在每次中断发生时,count会自增,并且当count累积到一定值时,LED1会翻转状态,实现LED的周期性闪烁。在这段代码中,count达到1时LED状态翻转,因此要实现约1秒的周期性闪烁,需要count累积到1。
/****************************************************************************
* 文 件 名: main.c
* 描 述: 定时器T1通过查询方式控制LED1周期性闪烁
****************************************************************************/
#include <ioCC2541.h>#define uchar unsigned char
#define uint unsigned int#define LED1 P1_0 // P1.0口控制LED1/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED灯相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{P1DIR |= 0x01; //P1.0定义为输出LED1 = 0; //使LED1灯下电默认为熄灭
}/****************************************************************************
* 名 称: InitT1()
* 功 能: 定时器初始化,系统不配置工作时钟时默认是2分频,即16MHz
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitT1()
{T1CTL = 0x0d; //128分频,自动重装 0x0000-0xFFFF T1STAT= 0x21; //通道0,中断有效
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{uchar count=0;InitLed(); //调用初始化函数InitT1();while(1){if(IRCON > 0){ IRCON=0;if(count++ >= 1) //约1s周期性闪烁,示波器测大约为1025MS{count=0;LED1 = !LED1; //LED1闪烁 }} }
}
2.5 定时器T3-中断方式
/****************************************************************************
* 文 件 名: main.c
* 描 述: 定时器T3通过中断方式控制LED1周期性闪烁
****************************************************************************/
#include <ioCC2541.h>#define uchar unsigned char
#define uint unsigned int#define LED1 P1_0 // P1.0口控制LED1uint count; //用于定时器计数/****************************************************************************
* 名 称: InitLed()
* 功 能: 设置LED灯相应的IO口
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitLed(void)
{P1DIR |= 0x01; //P1.0定义为输出LED1 = 0; //使LED1灯下电默认为熄灭
}/****************************************************************************
* 名 称: InitT3()
* 功 能: 定时器初始化,系统不配置工作时钟时默认是2分频,即16MHz
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitT3()
{ T3CTL |= 0x08 ; //开溢出中断 T3IE = 1; //开总中断和T3中断T3CTL |= 0xE0; //128分频,128/16000000*N=0.5S,N=62500T3CTL &= ~0x03; //自动重装 00->0xff 62500/255=245(次)T3CTL |= 0x10; //启动EA = 1; //开总中断
}//定时器T3中断处理函数
#pragma vector = T3_VECTOR
__interrupt void T3_ISR(void)
{ IRCON = 0x00; //清中断标志, 也可由硬件自动完成 if(count++ > 245) //245次中断后LED取反,闪烁一轮(约为0.5 秒时间) { //经过示波器测量确保精确count = 0; //计数清零 LED1 = ~LED1; //改变LED1的状态}
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{InitLed(); //设置LED灯相应的IO口InitT3(); //设置T3相应的寄存器while(1){};
}
2.6 串口通信--收发字符串
/****************************************************************************
* 文 件 名: main.c
* 描 述: 设置串口调试助手波特率:115200bps 8N1
* 串口调试助手给CC254x发字符串时,开发板会返回接收到的字符串
****************************************************************************/
#include <ioCC2541.h> //<ioCC2540.h>
#include <string.h>#define uchar unsigned char
#define uint unsigned int #define UART0_RX 1
#define UART0_TX 2
#define SIZE 51char RxBuf;
char UartState;
uchar count;
char RxData[SIZE]; //存储发送字符串/****************************************************************************
* 名 称: DelayMS()
* 功 能: 以毫秒为单位延时
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint len)
{ while(len--)for (int i=0; i<535; i++);
}/****************************************************************************
* 名 称: InitUart()
* 功 能: 串口初始化函数
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitUart(void)
{ PERCFG = 0x00; //外设控制寄存器 USART 0的IO位置:0为P0口位置1 P0SEL = 0x0c; //P0_2,P0_3用作串口(外设功能)P2DIR &= ~0xC0; //P0优先作为UART0U0CSR |= 0x80; //设置为UART方式U0GCR |= 11; U0BAUD |= 216; //波特率设为115200UTX0IF = 0; //UART0 TX中断标志初始置位0U0CSR |= 0x40; //允许接收 IEN0 |= 0x84; //开总中断允许接收中断
}/****************************************************************************
* 名 称: UartSendString()
* 功 能: 串口发送函数
* 入口参数: Data:发送缓冲区 len:发送长度
* 出口参数: 无
****************************************************************************/
void UartSendString(char *Data, int len)
{uint i;for(i=0; i<len; i++){U0DBUF = *Data++;while(UTX0IF == 0);UTX0IF = 0;}
}/****************************************************************************
* 名 称: UART0_ISR(void) 串口中断处理函数
* 描 述: 当串口0产生接收中断,将收到的数据保存在RxBuf中
****************************************************************************/
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{ URX0IF = 0; // 清中断标志 RxBuf = U0DBUF;
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{ CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振while(CLKCONSTA & 0x40); //等待晶振稳定为32MCLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ InitUart(); //调用串口初始化函数 UartState = UART0_RX; //串口0默认处于接收模式memset(RxData, 0, SIZE);while(1){if(UartState == UART0_RX) //接收状态 { if(RxBuf != 0) { if((RxBuf != '#')&&(count < 50))//以'#'为结束符,一次最多接收50个字符 RxData[count++] = RxBuf; else{if(count >= 50) //判断数据合法性,防止溢出{count = 0; //计数清0memset(RxData, 0, SIZE);//清空接收缓冲区}elseUartState = UART0_TX; //进入发送状态 }RxBuf = 0;}}if(UartState == UART0_TX) //发送状态 { U0CSR &= ~0x40; //禁止接收 UartSendString(RxData, count); //发送已记录的字符串。UartSendString("\r\n",2); //发送回车。U0CSR |= 0x40; //允许接收 UartState = UART0_RX; //恢复到接收状态 count = 0; //计数清0memset(RxData, 0, SIZE); //清空接收缓冲区} }
}
2.7 AD 采集 cc2530 温度串口显示
相关寄存器如下表所示
main.c
/****************************************************************************
* 文 件 名: main.c
* 描 述: ADC把芯片温度通过串口发给电脑,部分芯片误差较大需校准
* 手摸芯片温度有明显变化
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "UartTimer.h"#define HAL_ADC_REF_1V25 0x00
#define ADC_12_BIT 0x30
#define ADC_EMP_SENS 0x0E
#define ADC_TO_CELSIUS(ADC_VALUE) ((ADC_VALUE>>4)-334) //温度校正/****************************************************************************
* 名 称: InitSensor()
* 功 能: 温度传感器初始化函数
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitSensor(void)
{ DISABLE_ALL_INTERRUPTS(); //关闭所有中断 InitClock(); //设置系统主时钟为 32M TR0=0x01; //设置为1来连接温度传感器到SOC_ADCATEST=0x01; //使能温度传感
} /****************************************************************************
* 名 称: GetTemperature()
* 功 能: 获取温度传感器 AD 值
* 入口参数: 无
* 出口参数: 通过计算返回实际的温度值
****************************************************************************/
float GetTemperature(void)
{ unsigned int value; unsigned char tmpADCCON3 = ADCCON3;ADCIF = 0; //选择1.25V为参考电压;12位分辨率;对片内温度传感器采样ADCCON3 = (HAL_ADC_REF_1V25 | ADC_12_BIT | ADC_EMP_SENS); while(!ADCIF); //等待 AD 转换完成 value = ADCL >> 2; //ADCL 寄存器低 2 位无效 value |= (((unsigned int)ADCH) << 6);ADCCON3 = tmpADCCON3;return ADC_TO_CELSIUS(value);
}/****************************************************************************
* 程序入口函数
****************************************************************************/
void main(void)
{ char i; float AvgTemp; char strTemp[6];InitUART(); //初始化串口 InitSensor(); //初始化 ADC while(1) { AvgTemp = 0; for (i=0; i<64; i++) { AvgTemp += GetTemperature(); }AvgTemp = AvgTemp/64; //每次累加后除 64memset(strTemp, 0, 6);sprintf(strTemp,"%.02f", AvgTemp);//将浮点数转成字符串UartSendString(strTemp, 5); //通过串口发给电脑显示芯片温度UartSendString("\r\n",2);DelayMS(1000); //延时}
}
UartTimer.h
#include <ioCC2541.h>typedef unsigned char uchar;
typedef unsigned int uint;#define DISABLE_ALL_INTERRUPTS() (IEN0 = IEN1 = IEN2 = 0x00)//三个void InitClock(void)
{ CLKCONCMD &= ~0x40; //设置系统时钟源为 32MHZ晶振while(CLKCONSTA & 0x40); //等待晶振稳定 CLKCONCMD &= ~0x47; //设置系统主时钟频率为 32MHZ
}/****************************************************************************
* 名 称: InitT3()
* 功 能: 定时器初始化
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitT3(void)
{T3CCTL0 = 0x44; //T3CCTL0 (0xCC),CH0 中断使能,CH0 比较模式T3CC0 = 0xFA; //T3CC0设置为250T3CTL |= 0x9A; //启动T3计数器,计数时钟为16分频。使用MODULO模式IEN1 |= 0x08; IEN0 |= 0x80; //开总中断,开T3中断
}/****************************************************************************
* 名 称: InitUart()
* 功 能: 串口初始化函数
* 入口参数: 无
* 出口参数: 无
****************************************************************************/
void InitUART(void)
{PERCFG = 0x00; //位置1 P0口P0SEL = 0x3C; //P0用作串口P2DIR &= ~0xC0; //P0优先作为UART0 U0CSR |= 0x80; //串口设置为UART方式U0GCR |= 11; U0BAUD |= 216; //波特率设为115200UTX0IF = 1; //UART0 TX中断标志初始置位1 U0CSR |= 0x40; //允许接收IEN0 |= 0x84; //开总中断,接收中断
}/****************************************************************************
* 名 称: UartSendString()
* 功 能: 串口发送函数
* 入口参数: Data:发送缓冲区 len:发送长度
* 出口参数: 无
****************************************************************************/
void UartSendString(char *Data, int len)
{uint i;for(i=0; i<len; i++){U0DBUF = *Data++;while(UTX0IF == 0);UTX0IF = 0;}U0DBUF = 0x0A; //输出换行while(UTX0IF == 0);UTX0IF = 0;
}/****************************************************************************
* 名 称: DelayMS()
* 功 能: 以毫秒为单位延时 16M时大约为530,32M需要调整,系统时钟不修改默认为16M
* 入口参数: msec 延时参数,值越大,延时越久
* 出口参数: 无
****************************************************************************/
void DelayMS(uint msec)
{ uint i,j;for (i=0; i<msec; i++)for (j=0; j<1060; j++);
}