基于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-TXD 50(PS0)-RXD0
7-RXD 51(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
相关文章
|
7月前
|
芯片
STC15F100E单片机模拟串口
STC15F100E单片机模拟串口
STC15F100E单片机模拟串口
|
7月前
|
存储
单片机的指令系统
单片机的指令系统
60 1
|
7月前
|
监控
单片机的时钟系统
单片机的时钟系统
83 1
|
2月前
【通信协议讲解】单片机基础重点通信协议解析与总结之串口通信(三)
【通信协议讲解】单片机基础重点通信协议解析与总结之串口通信(三)
|
2月前
|
传感器 编解码 人机交互
基于51单片机的温室大棚环境检测系统
基于51单片机的温室大棚环境检测系统
71 0
|
7月前
|
传感器 数据采集 监控
LabVIEW单片机的废气再循环EGR检测系统
LabVIEW单片机的废气再循环EGR检测系统
53 0
|
7月前
|
传感器 存储 安全
基于单片机的定时温控系统的设计_kaic
基于单片机的定时温控系统的设计_kaic
|
6月前
单片机IO口模拟串口实现原理
单片机IO口模拟串口实现原理
102 5
|
7月前
|
传感器
基于51单片机的车辆倒车雷达报警系统
该文描述了一个基于51单片机的超声波倒车雷达系统设计,要求包括:2cm至4m的测量范围,3mm精度,集成DS18B20温度传感器以校准声速,使用LCD1602显示距离和温度,具备按键设置预警距离及蜂鸣器报警功能。系统由AT89C51单片机、HC-SR04超声波模块、DS18B20温度模块、报警电路和LCD显示电路组成。文中还展示了Proteus仿真电路图和部分仿真结果分析,包括LCD显示示例和预警距离设置操作。
|
7月前
|
语音技术 物联网 程序员
51单片机智能小车(循迹、跟随、避障、测速、蓝牙、wifie、4g、语音识别)总结-2
51单片机智能小车(循迹、跟随、避障、测速、蓝牙、wifie、4g、语音识别)总结-2
51单片机智能小车(循迹、跟随、避障、测速、蓝牙、wifie、4g、语音识别)总结-2