基于MC9S12XS128单片机的AD数据采集系统(HC-05蓝牙无线串口传输)-阿里云开发者社区

开发者社区> 王先森Vicent> 正文

基于MC9S12XS128单片机的AD数据采集系统(HC-05蓝牙无线串口传输)

简介: 10/19
+关注继续查看

基于MC9S12XS128单片机的AD数据采集系统(HC-05蓝牙无线串口传输)

image-20210825154550844
image-20210825154915027
%E6%B8%B2%E6%9F%93%E5%9B%BE.jpg

说明

对多个传感器进行供电,并采集传感器输出的模拟电压信号,无线传输至电脑接收终端,对数据进行保存分析。因为应用场景为采集光敏电阻及湿度传感器等传统的传感器信号,所以这里依然选择自带ADC的MC9S12XS128作为本次设计的主控芯片。由于应用主要是简单的ADC数据采集及无线串口传输,这里选择引脚数最少的封装LQFP64。如下图所示。

image-20210825161508975

硬件选型

MCU

MCU选择MC9S12XS128MAE(LQFP64),MC9S12XS128 是 16 位单片机,由 16 位中央处理单元(CPU12X)、128KB 程序、Flash(P-lash)、8KB RAM、8KB 数据 Flash(D-lash)组成片内存储器。LQFP64封装的现在某宝上有很多,但不一定都有货,价格也差别很大,下单前最好问一下客服有没有货,而且最近大部分芯片都在涨价。

无线传输

无线串口传输选用HC-05,最高可以实现1382400bps传输速率,传输距离10米,因为我们这里所接收端是电脑上的,且现在大多数台式电脑都自带蓝牙,所以HC-05只需要一个,用于连接MC9S12XS128就可以,电脑端只需要用自带的蓝牙接收HC-05的数据即可。为了使设计出的板子整体美观,这里选用贴片的HC-05,如下图所示,不同于常用的带底板的HC-05,贴片的HC-05核心板需要外围辅助电路才能正常工作。这里从HC-05使用手册上可以找到,对应的外围电路(手册上的有点糊,后面原理图上我有画,比较高清)。

image-20210825163717678

电源部分

5V电源

5v电源用于板载供电,来源包括 外部供电与锂电池供电,当处于外部供电时,通过usb口电源连接至LM2940-5.0输出5v电压用于板子整体供电(这里是加5v稳压芯片是为了保证板子电源以及后续锂电池充电不受usb口输出电压的影响,usb口5v电压输入情况下,LM2490实际输出会小于5v。这里usb口设计主要是用于对锂电池充电设计,所以只要最终大于4.65v即可,为啥是4.65v马上就会说明)。LM2940封装选用TO-263下面是我在手册上复制出来的封装引脚定义以及LM2940输入与输出电压说明。(特别注意的是检查 绘制的TO-263封装4引脚连接的为GND,不要设计成与3脚OUT或者1脚IN电气相同,否则会出现板子电源正负短接)

image-20210825171016836
  1. Input Voltage Range = 6 V to 26 V
  2. Dropout Voltage Typically 0.5 V at Iout=1A

为了实现无线数据采集及传输,当然需要一个内部电源对板子进行供电,而不是外接电源线进行实时供电,这样不就违背设计无线的初心了吗,那么现在需要一个内部电源进行供电,而现在锂电池的输出电压绝大部分都是3.7v的,而我们现在需要5v电压,所以肯定不能直接将锂电池接入板子上进行供电;同时,锂电池本身也需要充电,才能维持一段时间的持续供电。基于这些原因,我们需要选择一个锂电池充放电管理芯片,实现输出5v电压,以及可以为锂电池本身进行充电。这里我选用的是ESOP8封装的ip5306,该芯片可以实现5v 2.4A输出,输入电压范围为4.65v~5.5v。满足我们当前设计要求。当然我这里选择ip5306的原因一方面是因为引脚数少,方便焊接,一方面是方便后续的检测。如果想DIY设计更高级的,也可以选择比较强的芯片代替,比如支持多种快充协议的。大家按需选择。下图是Ip5306典型应用原理图。

ip5306典型简化应用原理图

3.3V电源

电路上的3.3v电源是对HC-05核心板进行供电使用,这里选用SOT-223封装的AMS1117-3.3,该芯片输入接上面所设计的5v电源,输出的3.3v电源对HC-05进行供电。同样需要注意下图红色标识引脚为Vout,而不是GND。

image-20210826163019981

串口部分

对比了CH340系列的串口芯片,选用最简的CH340N芯片,封装为sop-8,内置独立的收发缓冲区,支持通讯波特率100bps~2Mbps,这里2Mbps在串口通信里是相当大的了。

image-20210825183514208

需要注意的是,8引脚,大多数板子电源都为5v,所以,按照说明要求接0.1uf的退耦电容,不然在串口通信时会出现各种bug,尤其是通信波特率高的时候。1、2引脚,分别接接D+、D-。而6脚TXD接MCU的RXD,7脚RXD接TXD,这里需要特别注意,相同的连在一起将无法传输数据

CH340N串口引脚MCU串口引脚
6-TXD50(PS0)-RXD0
7-RXD51(PS1)-TXD0

硬件设计

原理图

%E7%94%B5%E8%B7%AF%E5%8E%9F%E7%90%86%E5%9B%BE.jpg

%E6%B8%B2%E6%9F%93%E5%9B%BE.jpg

总体原理图设计如上图所示。

渲染图是用keyshot9软件渲染的。

硬件选型 部分已经进行相关介绍,这里就不进行赘述了。在上面全部硬件焊接完成后,可以进行将锂电池接上,将供电开关S1拨至锂电池侧进行供电,正常情况下,锂电池电量LED指示灯点亮,以及电路电源指示灯点亮。连接上micro-usb数据线,将s2开关拨至DC电源侧,电池开始充电,电量指示灯最高指示灯开始闪烁,说明充电电路正常运行。

蓝牙HC-05配置

下面我们先对HC-05进行配置

HC-05进入AT模式

拨码开关sw4 1、2打开,其它保持关闭状态,先让HC-05的AT引脚置高进入AT模式,即按住按键sw1,接上micro-usb数据线,另一端接上电脑的usb口上进行上电,松开sw1,当D1灯变为慢闪,则表明HC-05已经进入AT模式;

查找COM号

我的电脑->右键->管理 打开界面如下,选择 设备管理器,下拉 端口,可以看到所连接板子的端口号为COM19(带CH340字样的端口)。

image-20210825204315460

开始AT模式调试

打开电脑的串口调试助手,设置波特率为38400bps(这里的波特率是HC-05进入AT模式后固定的)。

Screenshot%202021-08-25%20211534.jpg

配置蓝牙 (发送以下AT指令后返回OK表示设置成功)

  1. 恢复默认设置:AT+ORGL\r\n(\r\n即回车、换行,在串口调试助手上输入一个回车即可)
  2. 配置蓝牙的名称:AT+NAME=Bluetooth_M\r\n
  3. 配置蓝牙的配对码:AT+PSWD=1234\r\n(配对码设置为四位,需要记住,后面电脑连接配对时需要用到)
  4. 将蓝牙A配置为主机模式:AT+ROLE=1\r\n(板子实时采集数据并主动向外发送,所以设置为主机模式)
  5. 配置波特率、停止位和校验位:AT+UART=115200,0,0\r\n,设置蓝牙通信串口波特率为115200,停止位1位,无校验位(这里设置的波特率是当HC-05正常工作时的通信速率,而不是更改AT模式下固定的38400bps波特率)

电脑连接HC-05进行配对

上一步中,配置的蓝牙名称为Bluetooth_M、配对码为1234,一会我们会用到。

先对板子重新上电,使得HC-05进入正常模式

打开电脑蓝牙设置,电脑自带蓝牙的话,在桌面右下角可以看到蓝牙的图标,左键单击,选择 添加蓝牙设备,则可以打开如下界面,左键单击 添加蓝牙或其他设备,

image-20210825212519205

弹出如下列表,选择第一项,等待一会,就可以看到Bluetooth_M设备名称,左键单击,将会进行配对,将会弹出输入配对码的窗口,此时输入上一步设置的1234配对码,确认后便可配对上。如果未搜索到Bluetooth_M设备,请确认是否重新上电重启板子。

image-20210825212614841

至此,完成蓝牙的设置及配对工作,接下来,进行MCU程序编写。

亚克力外壳设计

为了提高板子本身的应用环境的绝缘抗噪性能,我这里将PCB导出的.stp文件导入进Rhino7(犀牛7),简单画了一下外壳,由四块亚克力板组成,外壳形状相信大家都看到了,下面内嵌的2600mAh锂电池尺寸为(7.1mm 46mm 70mm)。四块亚克力外壳加工.ai文件,在文章的最后,也会一并分享给大家。

image-20210825154915027

程序设计

文章最后会把该程序的工程文件打包分享给大家。

程序设计主要思路是通过MC9S12XS128的ADC口进行8通道数据采集(LQFP64封装只有PAD00~PAD07八个ADC引脚)。这里需要特别注意使用printf时

printf("%.3f,%.3f,%.3f,%.3f\n",channel1,channel2,channel3,channel4);

需要在main.c文件上加入TERMIO_PutChar函数,不需要在主函数中调用。否则无法串口打印输出数据。至于为什么可以看这篇文章

void TERMIO_PutChar(char C) 
{
  while(!(SCI0SR1&0x80));
  SCI0DRL=C;
}

本次程序设计的是通过8路ADC实现4路差分信号的采集,并实时通过串口输出,在这里即为HC-05串口输出。

这里是串口调试助手接收的数据截图,可以看到可以正常接收数据。

%E4%B8%B2%E5%8F%A3%E6%9C%89%E7%BA%BF115200%E9%80%9A%E4%BF%A1.jpg

关于程序是如何编写的我也不过多的说明,在下面的源代码中都有相应的中文注释,帮助理解。

在这里安利一下,如果大家目前想使用飞思卡尔MC9S12XS128这个芯片进行系统设计的话,一方面肯定是参考官方提供的最为权威,但我推荐入门看MC9S12单片机原理及嵌入式应用开发技术书上的讲解及示例都非常好,毕竟是中文的,,我在某东和某宝查了一下,现在出第二版的了,有条件的读者推荐购买纸质的,阅读体验肯定比电子版的好,我现在只找到第一版的分享给大家。

主程序main.c

#include <hidef.h>
#include "derivative.h"
#include <stdio.h>
#include "init.h"
void TERMIO_PutChar(char C) 
{
  while(!(SCI0SR1&0x80));
  SCI0DRL=C;
}
void main(void)
{
  float channel1,channel2,channel3,channel4;
  DisableInterrupts;        //关闭中断
    INIT_AD();               //AD初始化,八通道,8位
    INIT_PLL();
    INIT_SCI0();
    EnableInterrupts;         //打开中断
    for(;;)
    {
    while(!(ATD0STAT0&0X80));             //查询ATD是否完成
    channel1=(float)(channel_1L-channel_2L)*5/255;
    channel2=(float)(channel_3L-channel_4L)*5/255;
    channel3=(float)(channel_5L-channel_6L)*5/255;
    channel4=(float)(channel_7L-channel_8L)*5/255;
    printf("%.3f,%.3f,%.3f,%.3f\n",channel1,channel2,channel3,channel4);
    }
}

init.h

#include <hidef.h>
#define     channel_1H     ATD0DR0H
#define     channel_1L     ATD0DR0L
#define     channel_2H     ATD0DR1H
#define     channel_2L     ATD0DR1L
#define     channel_3H     ATD0DR2H
#define     channel_3L     ATD0DR2L
#define     channel_4H     ATD0DR3H
#define     channel_4L     ATD0DR3L
#define     channel_5H     ATD0DR4H
#define     channel_5L     ATD0DR4L
#define     channel_6H     ATD0DR5H
#define     channel_6L     ATD0DR5L
#define     channel_7H     ATD0DR6H
#define     channel_7L     ATD0DR6L
#define     channel_8H     ATD0DR7H
#define     channel_8L     ATD0DR7L

void INIT_PLL(void);
void INIT_SCI0(void);
void SCI0_send(unsigned char data); 
unsigned char SCI0_receive(void);
void INIT_SCI1(void);
void SCI1_send(unsigned char data); 
unsigned char SCI1_receive(void);
void init_pwm(void); 
void delay(void);
void INIT_AD(void); 
unsigned char AD_capture(unsigned char chanel); 
void initialize_tim(void);
void DFlash_Init(void);
void DFlash_Write(word ADDR16,word a,word b,word c,word d);
unsigned int DFlash_Read (word destination);
void DFlash_Erase(word ADDR16);
void SPI_Init(void);
byte SPI_Byte(byte value);

init.c

#include "derivative.h"      /* derivative-specific definitions */
#include "init.h"      

#define  BUS_CLOCK           80000000       //总线频率,改变总线频率直接在此处修改
#define  OSC_CLOCK           16000000       //晶振频率
#define   BAUD           115200      //串口波特率

#define READword(address)     ((unsigned int)(*(volatile unsigned int *__near)(address)))

#define DFLASH_LOWEST_START_PAGE        0x00        //定义data flash的起始页
#define DFLASH_START                    0x00100000  //定义data flash的起始地址
#define DFLASH_PAGE_SIZE                0x0400      //定义data flash的大小为1K.
#define DFLASH_PAGE_WINDOW_START        0x0800      //定义data flash页面窗口的起始地址

unsigned int duoji=7500;
unsigned int motor=1000;



/*************************************************************/
/*                      初始化锁相环                         */
/*************************************************************/
void INIT_PLL(void) 
{
    CLKSEL &= 0x7f;       //设置OSCCLK作为系统时钟
    PLLCTL &= 0x8F;       //禁止锁相环

    //PLLCLK=2×OSCCLK×(SYNR+1)/(REFDV+1), fbus=PLLCLK/2
    #if(BUS_CLOCK == 120000000) 
        SYNR = 0xcd;
    #elif(BUS_CLOCK == 104000000) 
      SYNR = 0xcc;
    #elif(BUS_CLOCK == 96000000) 
      SYNR = 0xcb;
    #elif(BUS_CLOCK == 88000000) 
      SYNR = 0xca;
    #elif(BUS_CLOCK == 80000000) 
      SYNR = 0xc9;
    #elif(BUS_CLOCK == 72000000) 
      SYNR = 0xc8;
    #elif(BUS_CLOCK == 64000000) 
      SYNR = 0xc7;
    #elif(BUS_CLOCK == 56000000) 
      SYNR = 0xc6;
    #elif(BUS_CLOCK == 48000000) 
      SYNR = 0xc5;
    #elif(BUS_CLOCK == 40000000) 
      SYNR = 0x44;
    #elif(BUS_CLOCK == 32000000)
      SYNR = 0x43;     
    #elif(BUS_CLOCK == 24000000)
      SYNR = 0x42;
    #elif(BUS_CLOCK == 16000000)
      SYNR = 0x01;

   #endif 

    REFDV = 0x81;
    PLLCTL |=0x70;  //使能锁相环
    asm NOP;
    asm NOP;
    while(!(CRGFLG&0x08)); //PLLCLK锁定
    CLKSEL |= 0x80;        //设置PLLCLK为系统时钟

}

/*************************************************************/
/*                        初始化SCI0                         */
/*************************************************************/
void INIT_SCI0(void) 
{
  SCI0BD = BUS_CLOCK/16/BAUD;   //设置SCI0波特率为115200
  SCI0CR1 = 0x00;        //设置SCI0为正常模式,八位数据位,无奇偶校验
  SCI0CR2 = 0x0c;        //允许接收和发送数据
}

/*************************************************************/
/*                       串口发送函数                        */
/*************************************************************/
void SCI0_send(unsigned char data) 
{
  while(!SCI0SR1_TDRE);         //等待发送数据寄存器(缓冲器)为空
  SCI0DRL = data;
}

/*************************************************************/
/*                       串口接收函数                        */
/*************************************************************/
unsigned char SCI0_receive(void) 
{
  while(!SCI0SR1_RDRF);          //等待发送数据寄存器满
  return(SCI0DRL);
}

/*************************************************************/
/*                        初始化SCI1                         */
/*************************************************************/
void INIT_SCI1(void) 
{
  SCI1BD = BUS_CLOCK/16/BAUD;   //设置SCI1波特率为115200
  SCI1CR1 = 0x00;        //设置SCI1为正常模式,八位数据位,无奇偶校验
  SCI1CR2 = 0x0c;        //允许接收和发送数据
}

/*************************************************************/
/*                       串口发送函数                        */
/*************************************************************/
void SCI1_send(unsigned char data) 
{
  while(!SCI1SR1_TDRE);         //等待发送数据寄存器(缓冲器)为空
  SCI1DRL = data;
}

/*************************************************************/
/*                       串口接收函数                        */
/*************************************************************/
unsigned char SCI1_receive(void) 
{
  while(!SCI1SR1_RDRF);          //等待发送数据寄存器满
  return(SCI1DRL);
}

/*************************************************************/
/*                        初始化PWM                          */
/*************************************************************/
void init_pwm(void) 
{
  PWMCTL_CON01= 1;   //通道01为16位的PWM
  PWMCTL_CON23= 1;   //通道23为16位的PWM
  PWMCTL_CON45= 1;   //通道45为16位的PWM

  PWMPOL_PPOL1= 1;   //通道的极性为高电平有效
  PWMPOL_PPOL3= 0;   //通道的极性为低电平有效,这一点很重要。
  PWMPOL_PPOL5= 1;   //通道的极性为高电平有效

  PWMPRCLK = 0x33;   //A时钟和B时钟的分频系数为8,频率为10MHz
  PWMSCLA  =    1;   //SA时钟频率为5MHz
  PWMSCLB  =    1;   //SB时钟频率为5MHz
  PWMCLK   = 0x20;   //45用SA时钟作为时钟源,01和23用A,B时钟
  PWMCAE   = 0x00;   //脉冲模式为左对齐模式

  PWMPER01  =  2000;   //通道01的频率为5KHz,用于H桥的驱动 
  PWMPER23  =  2000;   //通道23的频率为5KHz,用于H桥的驱动 
  PWMPER45  = 50000;   //周期10ms,用于舵机的驱动

  PWMDTY01  =  motor;    //通道01的占空比设置  
  PWMDTY23  =  motor;    //通道23的占空比设置
  PWMDTY45  = duoji;     //通道45的占空比设置

  PWME_PWME1=0;          //禁能通道01,使用时再将该位置一
  PWME_PWME3=0;          //禁能通道23,使用时再将该位置一
  PWME_PWME5=0;          //禁能通道45,使用时再将该位置一
}

/*************************************************************/
/*                        延时函数                           */
/*************************************************************/
void delay(void) 
{
unsigned int i;
for(i=0;i<50;i++) 
 {
  asm("nop"); 
 }
}

/*************************************************************/
/*                      初始化AD模块                         */
/*************************************************************/
void INIT_AD(void)
{
 ATD0CTL1 = 0x00;

 ATD0CTL2 = 0x40;
 ATD0CTL3 = 0xc0;
 ATD0CTL4 = 0x02;
 ATD0CTL5 = 0x30;
}

/*************************************************************/
/*                        起动AD转换                         */
/*************************************************************/
unsigned char AD_capture(unsigned char chanel) 
{
 unsigned char AD_data;
 switch(chanel)
 { 
  case 0:
    ATD0CTL5 = 0x00;    //转换AD00
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 1:
    ATD0CTL5 = 0x01;    //转换AD01
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 2:
    ATD0CTL5 = 0x02;    //转换AD02
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 3:
    ATD0CTL5 = 0x03;    //转换AD03
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 4:
    ATD0CTL5 = 0x04;    //转换AD04
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 5:
    ATD0CTL5 = 0x05;    //转换AD05
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 6:
    ATD0CTL5 = 0x06;    //转换AD06
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 7:
    ATD0CTL5 = 0x07;    //转换AD07
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 8:
    ATD0CTL5 = 0x08;    //转换AD08
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 9:
    ATD0CTL5 = 0x09;    //转换AD09
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 10:
    ATD0CTL5 = 0x0a;    //转换AD10
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 11:
    ATD0CTL5 = 0x0b;    //转换AD11
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 12:
    ATD0CTL5 = 0x0c;    //转换AD12
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 13:
    ATD0CTL5 = 0x0d;    //转换AD13
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 14:
    ATD0CTL5 = 0x0e;    //转换AD14
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

  case 15:
    ATD0CTL5 = 0x0f;    //转换AD15
    while(!ATD0STAT0_SCF);
    AD_data = ATD0DR0L;
    break;

 }
 return(AD_data);
}

/************************************************************/
/*                    初始化TIM模块                         */
/************************************************************/
void initialize_tim(void)
{
  TSCR1_TFFCA = 1;  // 定时器标志位快速清除
  TSCR1_TEN = 1;    // 定时器使能位. 1=允许定时器正常工作; 0=使主定时器不起作用(包括计数器)
  TIOS  = 0xfe;      //指定通道0为输入捕捉方式,其余通道为输出比较方式
  TCTL4 = 0x01;        // 设置通道0为捕捉上升沿方式
  TIE   = 0x01;     // 允许通道0定时中断
  TSCR2 = 0x07;        // 预分频系数pr2-pr0:111,时钟周期为1.6us,
  TFLG1 = 0xff;        // 清除各IC/OC中断标志位
  TFLG2 = 0xff;     // 清除自由定时器中断标志位
}

/*************************************************************/
/*                      初始化DFLASH                         */
/*            DFLASH的相对地址范围为0x0000-0x1fff            */
/*************************************************************/
void DFlash_Init(void)
{
   while(FSTAT_CCIF==0);            //等待正在处理的FLASH操作完成
   FCLKDIV=0x0F;                    //外部晶振为16M.FLASH时钟不超过1M,具体参照手册
   FCNFG=0x00;                      //禁止中断
   while(FCLKDIV_FDIVLD==0);        //等待时钟设置成功
}

/*************************************************************/
/*                     向DFLASH写入数据                      */
/*                ADDR16为写入数据的首地址                   */
/*                 a,b,c,d为写入的数据                    */
/*************************************************************/
void DFlash_Write(word ADDR16,word a,word b,word c,word d)
{
    while(FSTAT_CCIF==0); 
    if(FSTAT_ACCERR)           //判断并清除标志位;
        FSTAT_ACCERR=1;
    if(FSTAT_FPVIOL)           //判断并清除标志位;
        FSTAT_FPVIOL=1;
    FCCOBIX_CCOBIX=0x00; 
    FCCOB=0x1110;         //写入命令和高位地址
    FCCOBIX_CCOBIX=0x01;  //地址后16位
    FCCOB=ADDR16;         //写入低16位地址
    FCCOBIX_CCOBIX=0x02;  //写入第一个数据
    FCCOB=a;
    FCCOBIX_CCOBIX=0x03;  //写入第二个数据
    FCCOB=b;
    FCCOBIX_CCOBIX=0x04;  //写入第三个数据
    FCCOB=c;
    FCCOBIX_CCOBIX=0x05;  //写入第四个数据
    FCCOB=d;  
      

    FSTAT_CCIF=1;         //写入执行命令
    while(FSTAT_CCIF==0); //等待执行完毕

}

/*************************************************************/
/*                     由DFLASH读取数据                      */
/*              destination为读取数据的地址                  */
/*************************************************************/
word DFlash_Read (word destination)
{
    byte   lastepage;          //用于存储EPAGE的值
    byte   epage;              //用于计算EPAGE的值
    unsigned int data;         //读取出的数据

    lastepage = EPAGE;   //保存EPAGE的值
    
    epage = (byte)((DFLASH_LOWEST_START_PAGE)+(destination >>10));   //计算EPAGE
    EPAGE=epage;                                                     //给EPAGE赋值
     
    data = READword((destination & (DFLASH_PAGE_SIZE - 1)) + DFLASH_PAGE_WINDOW_START);  //读取页面窗口中的数据
    
    EPAGE= lastepage;       //恢复EPAGE的值
    
    return(data);

}

/*************************************************************/
/*                    擦除DFLASH的一个分区                   */
/*************************************************************/
void DFlash_Erase(word ADDR16)
{   
  while(FSTAT_CCIF==0);
  if(FSTAT_ACCERR)           //判断并清除标志位;
      FSTAT_ACCERR=1;
  if(FSTAT_FPVIOL)           //判断并清除标志位;
      FSTAT_FPVIOL=1;

  FCCOBIX_CCOBIX=0x00;
  FCCOB=0x1210;           //写入擦除命令和高位地址
  FCCOBIX_CCOBIX=0x01;   
  FCCOB=ADDR16;           //写入低16位的地址
  FSTAT_CCIF=1;           //启动执行命令
  while(FSTAT_CCIF==0);   //等待执行完成
}

/*************************************************************/
/*                      初始化SPI模块                        */
/*************************************************************/
void SPI_Init(void) 
{
  DDRS    = 0xE0;  //设置接口为输出   
  SPI0CR2 = 0x00;  //SS管脚为普通I/O
  SPI0CR1 = 0x5e;  //使能SPI,设置为主模式
  SPI0BR  = 0x83; //设置波特率为1M                  
}

/*************************************************************/
/*                      SPI读写一个字节                      */
/*************************************************************/
byte SPI_Byte(byte value)
{
    while (!SPI0SR_SPTEF);
    SPI0DRL = value;
    while(!(SPI0SR_SPIF));
    return SPI0DRL;
}

关于程序下载

编译与下载程序需要软件codewarrior以及BDM下载器(飞翔)

BDM驱动安装可以看我之前写的文章里面有相关的介绍,也可以配合看MC9S12单片机原理及嵌入式应用开发技术第三章中安装教程。

包括驱动文件下载,及codewarrior的下载链接,这里就不重复了。

1.jpg

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【Hadoop Summit Tokyo 2016】现代化企业级数据仓库:数据湖泊
本讲义出自CHARLES SEVIOR在Hadoop Summit Tokyo 2016上的演讲,主要分享了面对企业级数据仓库向着数据量剧增、实时处理数据的需求增加以及数据分析的需求不断涌现的情况,如何定制个性化以及增强的现代化企业级数据仓库服务成为了一项巨大的挑战,而面对这样的挑战使用数据湖泊技术成为了一种新的解决方案。
1659 0
PageAdmin Cms建站系统如何修改后台登录目录
pageadmin修改后台登录目录的解决办法
259 0
带噪声的1KHz微弱信号采集系统设计仿真及制PCB板过程
一、题目:基于单片机的系统设计    增加:增加前端模拟部分信号处理 仪器放大器+带通滤波器 功能:实现对带噪声的1KHz微弱信号的数据采集(信号幅度100mV) 二、设计要求及完成情况   1、四层板,大小150mm*95mm      ①实验截图    ②问题及心得    书中和许多的教程中只有双层板的教学,打开原理图布局的时候,下方的标签显示的是Top Layer和Bottom Layer,也就是仅有两层的板子。
1014 0
利用Spark Streaming实现分布式采集系统
之前我在微信朋友圈发了一段话,说明Spark Streaming 不仅仅是流式计算,也是一类通用的模式,可以让你只关注业务逻辑而无需关注分布式相关的问题而迅速解决业务问题.
3052 0
日志采集框架Flume、Flume介绍、概述、运行机制、Flume采集系统结构图(1、简单结构、复杂结构)
1. 日志采集框架Flume 1.1 Flume介绍 1.1.1 概述 1.Flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。 2.Flume可以采集文件,socket数据包等各种形式源数据,又可以将采集到的数据输出到HDFS、hbase、hive、kafka等众多外部存储系统中 3.一般的采集需求,通过对flume的简单配置即可实现
2551 0
分布式海量日志采集、聚合和传输系统:Cloudera Flume
导读:本文介绍了分布式海量日志采集、聚合和传输系统Cloudera Flume相关内容,Flume是Cloudera提供的日志收集系统,Flume支持在日志系统中定制各类数据发送方。
994 0
ML之DR之PCA:利用PCA对手写数字图片识别数据集进行降维处理(理解PCA)
ML之DR之PCA:利用PCA对手写数字图片识别数据集进行降维处理(理解PCA)
16 0
1-关于单片机通信数据传输(中断发送,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)
写这篇文章的目的呢,如题目所言,我承认自己是一个程序猿.....应该说很多很多学单片机的对于...先不说别的了,,无论是学51的还是32的,,,先问一下大家用串口发送数据的时候是怎么发的???如果发整型的数据是怎么发的??如果发浮点型的是怎么发的????再问大家串口接收数据是怎么接收的????亲们有...
1504 0
+关注
王先森Vicent
You may create better art.
32
文章
0
问答
来源圈子
更多
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载