历史上的今天
返回首页

历史上的今天

今天是:2025年06月05日(星期四)

正在发生

2018年06月05日 | STM32直接存储器访问DMA

2018-06-05 来源:eefocus

第一次接触DMA是在学校学习ARM9裸板程序的时候,想起来都时隔快2年了。现在来看看STM32平台的DMA,一样,在标准外设库的支持下,STM32的DMA编程十分简单,但是既是学习,那还是花点时间看看DMA的相关概念及原理的了解下。

1. DMA简介

DMA是Direct Memory Access的简称,是直接存储器访问的意思。DMA是STM32单片机的外设之一,主要功能是用来搬移数据的。通过DMA搬移数据不需要CPU直接参与控制,也不需要中断处理方式那样保留现场和恢复现场。在传输数据的时候,CPU可以干其他事情。

无使用DMA的数据传输: 
这里写图片描述

使用DMA后的数据传输: 
这里写图片描述

DMA数据传输支持从外设到存储器、存储器到外设、存储器到存储器(这里所讲的存储器可以是SRAM,也可以是FLASH)。DMA控制器包含了DMA1控制器和DMA2控制器,分别由7和5个通道作为数据传输。每个通道专门用来管理来自一个或者多个外设对存储器访问的请求,还有一个仲裁器用于协调各个外设对DMA传输请求的优先权。注意,DMA2只存在于大容量或互联型的STM32单片机中。

2. DMA功能框图

这里写图片描述

2.1 STM32外设对DMA的请求及通道

请求及通道对应图中的标号1和标号2:STM32外设想要通过DMA来传输数据,需先给DMA控制器发送DMA请求,控制器在收到外设的DMA请求之后会给外设一个应答信号,外设应答且DMA控制器收到外设的应答后,DMA启动传输,直至传输完毕。 
为什么需要发出请求,应答和接收应答这几个繁琐的步骤?由图中蓝色框框可以看出,DMA传输和CPU是共用系统总线的,要启动DMA传输的前提是系统总线是空闲的,换句话说是CPU没有占用系统总线,所以启动DMA传输前需要以上几个应答机制,其最底层是DMA控制器和CPU正为系统总线作出协调。DMA1有7个通道,DMA2有5个通道,不同的外设请求要通过对应的DMA通道发给DMA控制器。将不同的外设请求传输至对应的通道,这个是我们在软件编程上设置的。

DMA1开放的通道及对应请求: 
这里写图片描述 
DMA2开放的通道及对应请求: 
这里写图片描述 
虽然每个通道可以接收多个外设的请求,但是同一时间内只能接收一个。

2.2 仲裁器

仲裁器对应图中的标号3:当DMA控制器的多个通道发生DMA请求时,就需要仲裁器管理响应处理的顺序。仲裁器通过软件和硬件来管理DMA请求:软件指的是我们写的代码,在DMA_CCRx(x指通道号)寄存器中设置,有4个等级,非常高(DMA_Priority_VeryHigh)、高(DMA_Priority_High)、中(DMA_Priority_Medium)和低(DMA_Priority_Low)。硬件则是指若有两个或以上的DMA通道请求设置的优先级一样,则它们的响应顺序取决于通道编号,编号低者优先级高,在有DMA2的STM32中,DMA1控制器拥的响应优先级高于DMA2。

2.3 配置DMA控制器

配置DMA控制器,无非就是下图这几个寄存器: 
这里写图片描述

前面说到,DMA数据传输机制并不需要CPU的参与,但是DMA控制器要正常工作,数据要正确传输,需有三个必要条件:源地址、目的地址和数据大小,对于数据分批传输的情况,数据大小这个条件还包含每次传输的大小及单位。

(1)源地址和目的地址 
DMA的传输数据的方向有三个:从外设到存储器、从存储器到外设、从存储器到存储器。DMA_CCR的BIT[4]DIR就是用于配置数据传输方向的: 
这里写图片描述
取值为0表从外设到存储器,取值为1表从存储器到外设。外设地址在DMA_CPAR寄存器配置,存储器地址在DMA_CMAR寄存器配置。 
这里写图片描述

(2)传输数据的大小及单位 
以串口向电脑发送数据为例(存储器->外设方向),开发板软件可以一次性给电脑发送大量数据,具体多少在DMA_CNDTR配置: 
这里写图片描述
DMA_CNDTR低16位有效,一次最多只能传输65535个数据。 
数据要正确传输,源、目标存储的数据宽度必须一致。串口数据寄存器是8位的,也就是外设数据宽度设置寄存器DMA_CCRx的BIT[9:8]PSIZE取值为0: 
这里写图片描述 
存储器的数据宽度设置寄存器DMA_CCRx的BIT[11:10]MSIZE取值也为0: 
这里写图片描述 
DMA传输数据,还需要设置源地址上的数据发送指针和目的地址数据存放指针的增量模式。开发板串口向电脑发送数据,假设要发送的数据很多,那么存储器(源地址)上数据发送指针每次发送完毕需要加1,而串口数据寄存器则不需要,因为该寄存器只有一个,数据寄存器上的数据传送到电脑后被清空了(就算不清空,数据直接覆盖也没关系)。外设的地址指针增量模式由DMA_CCRx的PINC配置,存储器的地址指针则由MINC配置。 
这里写图片描述

(3)传输结束 
DMA中断状态寄存器DMA_ISR可以设置每个DMA通道传输过半、传输完成和传输错误示产生对应标志, 
这里写图片描述 
这里写图片描述 
在DMA_CCRx位1、2、3可以设置发生传输过半、传输完成和传输错误时产生中断: 
这里写图片描述 
另外补充一点,位0用于使能DMA传输 
这里写图片描述 
传输完成分两种模式:一次传输和循环传输,一次传输指传输一次后就停止,要再传输需要关闭DMA使能后重新配置后才能继续传输。循环传输则是一次传输完成后又恢复第一次传输时的配置循环传输,如此循环。设置位在DMA_CCRx寄存器的CIRC。

3. DMA功能模块描述结构体

标准库的一贯风格,在stm32f10x_dma.h文件中定于可DMA_InitTypeDef初始化结构体,DMA_Init()函数定义在stm32f10x_dma.c中。

typedef struct

{

  uint32_t DMA_PeripheralBaseAddr;  //外设地址

  uint32_t DMA_MemoryBaseAddr;      //存储器地址

  uint32_t DMA_DIR;                 //传输方向

  uint32_t DMA_BufferSize;          //传输的数据的数目大小

  uint32_t DMA_PeripheralInc;       //外设地址的增量模式

  uint32_t DMA_MemoryInc;           //存储器地址的增量模式

  uint32_t DMA_PeripheralDataSize;  //外设数据宽度

  uint32_t DMA_MemoryDataSize;      //存储器数据宽度

  uint32_t DMA_Mode;                //模式选择

  uint32_t DMA_Priority;            //通道优先级

  uint32_t DMA_M2M;                 //存储器到存储器模式

}DMA_InitTypeDef;

(1)DMA_PeripheralBaseAddr:外设地址,若是存储器到存储器模式,此成员设置为其中一个存储器的地址,否则设置为外设的地址。 
(2)DMA_MemoryBaseAddr:存储器地址,一般设置为程序中存放数据的容器(数组)的首地址。 
(3)DMA_DIR:传输方向,可设置为外设到存储器,存储器到外设。注意这里没有存储器到存储器的选项,当使用存储器到存储器时,只需要把其中一个存储器当做外设使用。 
(4)DMA_BufferSize:设定待传输数据数目。(5)DMA_PeripheralInc:外设地址增量模式,若取值为DMA_PeripheralInc_Enable表使能外设地址自动递增功能。一般外设都是只有一个数据寄存器,所以不会使能该位。 
(6)DMA_MemoryInc:若配置为DMA_MemoryInc_Enable表使能存储器地址自动递增功能。一般存储器都是我们自定义的,区域内存放多个数据,所以一般使能该位。 
(7)DMA_MemoryDataSize:外设数据宽度,可选8位(字节)、16位(半字)、32位(字) 
(8)DMA_MemoryDataSize:存储器数据宽度,可选8位(字节)、16位(半字)、32位(字) 
(9)DMA_Mode:传输模式选择,一次传输或循环传输 
(10)DMA_Priority:通道优先级设置,非常高、高、中、低可选 
(11)DMA_M2M:存储器到存储器模式

4. 编程常用函数

4.1 DMA时钟使能

4.2 初始化DMA功能模块描述结构体


函数原型:void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)

DMAy_Channelx指定哪一个DMA通道,DMA_InitStruct就是前面解析的描述结构体

使用示例:DMA_Init(DMAy_Channel1, &DMA_InitStruct);


4.3 使能外设DMA发送


以启动DMA发送功能为例:


函数原型:void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState 

NewState)

使用示例:

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);


外设的DMA传输需要相应的设置,而存储器是不需要的。存储器到存储器,在DMA_InitTypeDef结构体中有DMA_M2M成员需要开启。


4.4 使能DMA通道,开启DMA传输


函数原型:void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

使用示例:DMA_Cmd(DMAy_Channel1, ENABLE);

使能之后,DMA控制器开始工作,在合适的时机(CPU无占据总线)开始DMA控制下的数据传输。


4.5 查询DMA传输状态 

在DMA传输过程中,我们可以通过函数来查询传输通道的状态:


函数原型:FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)

假设要查询DMA通道4传输是否完成:

DMA_GetFlagStatus(DMA1_FLAG_TC4);

返回值为RESET表示传输尚未完成,SET表传输完成。


获取当前剩余数据量大小的函数:

函数原型:uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

使用示例,获取DMA通道4还有多少数据没有传输:

DMA_GetCurrDataCounter(DMAy_Channel4);


5. 编程实践


5.1 DMA传输–存储器到存储器模式


硬件平台是正点原子MiniSTM32,板载有两个LED分别为红色和绿色。 

程序功能实现把STM32内置的FLASH数据拷贝到内置的SRAM中:定义一个const静态变量为源数据,使用DMA传输将源数据拷贝到目标地址中,比对源数据和目标数据是否相同,若相同亮绿色LED灯,反之亮红色LED灯。 

DMA的编程核心在于 

(1)使能DMA时钟 

(2)配置DMA初始化结构体参数 

(3)使能DMA,开始进行数据传输 

(4)等待数据传输完成

工程结构为: 
这里写图片描述

BSP_LED.c实现配置LED引脚:

#include


void LED_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitTypeStu;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);


    //³õʼ»¯PA8ÍÆÍìÊä³ö

    GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitTypeStu);        

    GREEN_LED_OFF;


    GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_2;

    GPIO_Init(GPIOD, &GPIO_InitTypeStu);

    RED_LED_OFF;

}


BSP_USART.c实现配置USART1功能:



#include "BSP_USART.h"


#pragma import(__use_no_semihosting)                             

struct __FILE 

    int handle; 


}; 


FILE __stdout;          

_sys_exit(int x) 

    x = x; 


int fputc(int ch, FILE *f)

{      

    while((USART1->SR&0X40) == RESET);

    USART1->DR = (u8) ch;      

    return ch;

}


void NVIC_Configuration(void)

{

    NVIC_InitTypeDef NVIC_InitStu;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);


    NVIC_InitStu.NVIC_IRQChannel = USART1_IRQn;

    NVIC_InitStu.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStu.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStu.NVIC_IRQChannelCmd = ENABLE;


    NVIC_Init(&NVIC_InitStu);

}


void USART_Configuration(void)

{

    GPIO_InitTypeDef GPIO_InitStu;

    USART_InitTypeDef USART_InitStu;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);


    GPIO_InitStu.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStu.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStu.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStu);


    GPIO_InitStu.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_InitStu.GPIO_Pin = GPIO_Pin_10;

    GPIO_Init(GPIOA, &GPIO_InitStu);


    USART_InitStu.USART_BaudRate = 115200;

    USART_InitStu.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    USART_InitStu.USART_Parity = USART_Parity_No;

    USART_InitStu.USART_StopBits = USART_StopBits_1;

    USART_InitStu.USART_WordLength = USART_WordLength_8b;

    USART_InitStu.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_Init(USART1, &USART_InitStu);


    NVIC_Configuration();


    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);



    USART_Cmd(USART1, ENABLE);

}


void USART_SendChar(USART_TypeDef* pUSARTx, uint8_t c)

{

    USART_SendData(pUSARTx, c);


    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

}


void USART_SendString(USART_TypeDef* pUSARTx, char* str)

{

    uint32_t n = 0;


    while (*(str + n) != '\0')

    {

        USART_SendChar(pUSARTx, *(str + n));

        n++;

    }


    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

}


以上在前面相关文章都已经写过,下来看BSP_LED.c,实现对DMA功能的配置:


#include


void DMA_Configuration(const uint32_t *SrcBuf, uint32_t *destBuf, uint32_t BUF_SZ)

{

    DMA_InitTypeDef DMA_InitTypeStu;


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


    DMA_InitTypeStu.DMA_BufferSize = BUF_SZ;

    DMA_InitTypeStu.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitTypeStu.DMA_M2M = DMA_M2M_Enable;

    DMA_InitTypeStu.DMA_MemoryBaseAddr = (uint32_t)SrcBuf;

    DMA_InitTypeStu.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

    DMA_InitTypeStu.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitTypeStu.DMA_Mode = DMA_Mode_Normal;

    DMA_InitTypeStu.DMA_PeripheralBaseAddr = (uint32_t)destBuf;

    DMA_InitTypeStu.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

    DMA_InitTypeStu.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

    DMA_InitTypeStu.DMA_Priority = DMA_Priority_VeryHigh;


    DMA_Init(DMA1_Channel1, &DMA_InitTypeStu);


    DMA_Cmd(DMA1_Channel1, ENABLE);

}


uint8_t BufCmp(const uint32_t* pSrc, uint32_t* pDest, uint32_t len)

{

    int i;


    for (i = 0; i < len; i++)

    {

        if (*(pSrc + i) != *(pDest + i))

            return 1;

    }

    return 0;

}


main()函数:


#include

#include

#include


#define BUF_SZ  32


const uint32_t SrcBuf[BUF_SZ] = {0x12, 0x23, 0x45, 0x86, 0x45, 0x63, 0x89, 0x87, 

                                0x22, 0x23, 0x26, 0x27, 0x28, 0x31, 0x33, 0x86,

                                0x12, 0x23, 0x45, 0x86, 0x45, 0x63, 0x89, 0x87, 

                                0x22, 0x23, 0x26, 0x27, 0x28, 0x31, 0x33, 0x86};


uint32_t destBuf[BUF_SZ];


void delay_time(void)

{

    int i, j;


    for (i = 0; i < 500; i++)

        for (j = 0; j < 6000; j++);

}



int main(void)

{

    int i;


    LED_Configuration();

    USART_Configuration();

    DMA_Configuration(SrcBuf, destBuf, BUF_SZ);


    delay_time();

#if 0   

    for (i = 0; i < BUF_SZ; i++)

    {

        printf("SrcBuf[%d] = %u\r\n", i, SrcBuf[i]);

    }   


    printf("\r\n");

    for (i = 0; i < BUF_SZ; i++)

    {

        printf("destBuf[%d] = %u\r\n", i, destBuf[i]);

    }

#endif


#if 1   

    if (BufCmp(SrcBuf, destBuf, BUF_SZ) == 0)

    {

        GREEN_LED_ON;

        RED_LED_OFF;

    }


    else

    {

        GREEN_LED_OFF;

        RED_LED_ON;

    }


#endif

    while (1);  


    return 0;

}


5.2 存储器到串口(外设)模式


//BSP_DMA.c

void DMA_Configuration(const uint32_t *SrcBuf, uint32_t *destBuf, uint32_t BUF_SZ)

{

    DMA_InitTypeDef DMA_InitTypeStu;


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


    DMA_InitTypeStu.DMA_BufferSize = BUF_SZ;

    DMA_InitTypeStu.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitTypeStu.DMA_M2M = DMA_M2M_Disable;

    DMA_InitTypeStu.DMA_MemoryBaseAddr = (uint32_t)SrcBuf;

    DMA_InitTypeStu.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

    DMA_InitTypeStu.DMA_MemoryInc = DMA_MemoryInc_Enable;

    //DMA_InitTypeStu.DMA_Mode = DMA_Mode_Normal;

    DMA_InitTypeStu.DMA_Mode = DMA_Mode_Circular;       //循环发送

    DMA_InitTypeStu.DMA_PeripheralBaseAddr = (uint32_t)destBuf;     //(uint32_t)(USART1_BASE + 0x04);

    DMA_InitTypeStu.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

    DMA_InitTypeStu.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitTypeStu.DMA_Priority = DMA_Priority_VeryHigh;


    DMA_Init(DMA1_Channel4, &DMA_InitTypeStu);


    DMA_Cmd(DMA1_Channel4, ENABLE);

}


//main.c

int main(void)

{

    LED_Configuration();

    USART_Configuration();

    DMA_Configuration((const uint32_t*)SrcBuf, (uint32_t*)(&USART1->DR), BUF_SZ);  //(uint32_t*)(USART1_BASE + 0x04)


    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);


    while(1)

    {

        GREEN_LED_ON;

        RED_LED_OFF;


        delay_time();


        GREEN_LED_OFF;

        RED_LED_ON;


        delay_time();


    }

    return 0;

}


DMA控制下,SRAM上的数据不断向USART1的DR寄存器发送,这个过程CPU是不需要参与的,所以LED闪烁也一直在进行。


DMA传输其实很简单,被我说得有点啰嗦了。关键在于概念的理解吧,库函数的使用还是关键,寄存器操作基本不需要用到。

推荐阅读

史海拾趣

DIOTECH公司的发展小趣事

在市场竞争日益激烈的背景下,DIOTECH公司意识到单靠技术突破已经难以保持领先地位。于是,公司开始积极探索创新驱动和跨界合作的发展路径。通过与多家知名科技公司的合作,DIOTECH成功将人工智能技术应用于其产品中,推出了一系列具有智能化功能的电子产品。这些产品在市场上引起了强烈反响,为公司带来了新的增长点。

Cliff Electronic Components公司的发展小趣事

在市场竞争日益激烈的背景下,DIOTECH公司意识到单靠技术突破已经难以保持领先地位。于是,公司开始积极探索创新驱动和跨界合作的发展路径。通过与多家知名科技公司的合作,DIOTECH成功将人工智能技术应用于其产品中,推出了一系列具有智能化功能的电子产品。这些产品在市场上引起了强烈反响,为公司带来了新的增长点。

台湾凌通(Generalplus)公司的发展小趣事
检查控制电路中的其他元件(如继电器、晶体管等)是否工作正常,有无损坏或接触不良的情况。
Dover Corporation公司的发展小趣事

Dover Corporation自上市以来,一直保持着持续盈利和向投资者发放红利的记录。公司凭借其强大的业务能力和稳健的财务状况,赢得了投资者的信任和支持。这一成绩的取得不仅彰显了Dover在业务运营方面的实力,也为其未来的发展奠定了坚实的基础。

请注意,以上故事框架仅为概述性质,具体细节和数据可能需要根据Dover Corporation的实际情况进行调整和补充。

Aces Electronics Co Ltd公司的发展小趣事

随着技术的不断进步和产品的日益成熟,Aces开始将目光投向国际市场。公司积极参与国际电子展会和技术交流,与多家国际知名企业建立了合作关系。通过引进国外先进的技术和管理经验,Aces不断提升自身竞争力,逐渐在国际市场上占据了一席之地。同时,公司还积极拓展海外市场,将产品销往全球多个国家和地区。

ACCRETECH公司的发展小趣事

Aces Electronics Co., Ltd.自成立之初,就致力于电子技术的研发与创新。在公司发展早期,Aces面临技术壁垒和市场竞争的双重压力。然而,公司通过不断投入研发资源,终于在某一关键领域取得了重大技术突破,推出了一款具有颠覆性的电子产品。这款产品凭借其卓越的性能和创新的设计,迅速在市场上获得了广泛认可,为Aces打开了新的发展空间。

问答坊 | AI 解惑

示波器上居然是正弦波

来自EEWORLD合作群:arm linux fpga 嵌入0(49900581) 群主:wangkj…

查看全部问答>

修改platform.reg要重新sysgen吗?

RT 呵呵,搞了这么久,这个问题没搞清,失败啊…

查看全部问答>

CVOImage应用PNG,背景不透明

问91program:在eeworld下了你上传的CVOImage类后,发现显示PNG图片,但是发现PNG的背景是白色,不是透明, 请问这是这个类本身的原因,还是因为使用不对的原因。其他有没有谁用过CVOImgae的??…

查看全部问答>

定制Wince系统的疑问

1.当我们定制一个系统时候,在NEW platform wizard中要选择对应与开发板的BSP,是不是就是类似于应用层软件的SDK啊? 2.我看过一个资料,上面说BSP包含BOOTLOADER,OAL以及设备驱动等,那platform wizard中的BSP不包括bootloader,是不是bootloader ...…

查看全部问答>

各位大侠,这堆MOS管主要发挥什么作用?

本人正在学习电动工具电路设计,看到一款电钻的电池包中的一个电路板,其中有多达12块同型号MOS管,不太懂这块电路板中为何用到如此多的MOS管?这些电路的作用和功能是什么?如何选择MOS管型号和关键指标?叩谢 [ 本帖最后由 lord 于 2011-10- ...…

查看全部问答>

ads对arm的仿真

我买的是一个lpc2131的arm板子然后总是出现以下情况,我用的是jlink,这样之后就没法烧代码了,然后只有用j-tag烧写之后才能重新编码?我用的烧写方式是debugInRam,另外与debuginflash,reinflash这三种方式有什么区别?…

查看全部问答>

想了解下STM32读写Flash和中断同时存在的处理思路

写过两款STM32芯片的程序,STM32F107和STM32F207,但总感觉Flash这一块用的不爽。随便说说,当发牢骚了,万一有路过的大神刚好看到了,而恰巧您又有时间的话,给暂指导指导思路那必然也是极好的。     首先,是写Flash,在F1里,Flash倒 ...…

查看全部问答>

C5509A中断函数与中断向量表关联的问题

我是想通过定时器0实现中断定时void PLL_init() { CLKMD = 0x2cd4; //fclk = 100MHz, clkout = 50MHz }void timer0_init() { PRD0 = 9999; PRSC0 = 9; TCR0 = 0x0D38; //TOUT = 500Hz } void INT_init() { ST1_55 |= 1…

查看全部问答>

Z-STACK开发者指南___最新翻译

最近学习zigbee看到不错的资料,与大家分享: …

查看全部问答>