STM32实现USART+DMA接收未知长度的数据和发送

发布者:真诚友谊最新更新时间:2018-06-08 来源: eefocus关键字:STM32  USART  DMA接收 手机看文章 扫描二维码
随时随地手机看文章

前言:开始学USART+DMA的时候看到帖子《STM32 UART DMA实现未知数据长度接收》,觉得方法妙极了。此下出自此帖子——(整体的思路是这样的,一开始设置好DMA接收,可以把缓冲区长度设置为帧最大长度,我们可以把RX连接到定时器的管脚输入端,并且一开始设置输入并且使能引脚下降沿中断,当帧的第一个字节发送时,因为起始位为低电平,空闲时UART为高电平,满足条件,进入中断,禁止中断,并且在中断中开启定时器,该定时器工作在复位模式,上升沿复位,并且设置好定时器输出比较值为超时时间,比如20ms,这样,在传输后面字节时,肯定会有高低电平出现,即便是传输的是0x00,0xFF,虽然UART数据区不变,但是都为1,或都为0,但是因为起始位为低电平,停止位是高电平,所以肯定会有上升沿,定时器会一直复位,输出定时器的计数器一直到达不了输出比较值,当一帧传输结束后,定时在最后一个字节复位后,由于没有数据继续到达,无法复位,则计数器就能计到输出比较值,这时发出中断,在定时器中断中可以计算出接收数据的长度,并且通知外部数据已经接收完毕。)


今天我在工作中调通了另一种USART+DMA接收未知数据长度的接收,使用的是USRAT空闲总线中断接收,这种方法也在网站上比较多见,以前没试过,今天才知道如此的爽,另外我使用DMA发送USART数据替代了以前的查询法发送,发现更加爽了。其速度快了很多,尤其是在大量数据传输与发送的时候其优势更加明显。
我举个例子:1、后台数据->USART1-> USART2->其它设备,其它设备数据->USART2-> USART1->后台,这两个数据过程也可能同时进行。
2、由于硬件的限制,USART1和USART2的传输波特率不一样,比如USART1使用GPRS通信,USART2使用短距离无线通信;或者USART1使用以太网通信,USART2使用485总线通信。
由于在寝室只有笔记本电脑,只有一个串口转USB,没办法实现两个串口之间的数据转发了,只好实现串口各自的数据转发。
现在我把我实现的过程简单描述一下:
1、        初始化设置:USART1_RX+DMA1_ Channel5,USART2_RX+DMA1_ Channel6,USART1_TX+DMA1_ Channel4,USART2_TX+DMA1_ Channel7(具体设置请看程序包)。
2、        当数据发送给USART1接收完毕时候会引起USART1的串口总线中断,计算DMA1_ Channel5内存数组剩余容量,得到接收的字符长度。将接收的字符给DMA1_ Channel4内存数组,启动DMA1_ Channel4通道传输数据,(传输完成需要关闭。)下一次数据接收可以在启动DMA1_ Channel4时候就开始,不需要等待DMA1_ Channel4数据传输完成。但是上一次DMA1_ Channel4完成之前,不可以将数据给DMA1_ Channel4内存数组,会冲掉以前数据。
3、        USART2类同USART1。
,下面贴程序:IO口定义:
void GPIO_Configuration(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        /* 第1步:打开GPIO和USART部件的时钟 */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        /* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        /* 第3步:将USART Rx的GPIO配置为浮空输入模式
        由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
        但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
        */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        /* 第1步:打开GPIO和USART2部件的时钟 */
        //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        /* 第2步:将USART2 Tx的GPIO配置为推挽复用模式 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        /* 第3步:将USART2 Rx的GPIO配置为浮空输入模式
                由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
                但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
        */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        /*第3步已经做了,因此这步可以不做
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        */
        GPIO_Init(GPIOA, &GPIO_InitStructure);
}
串口初始化:
void USART_Configuration(void)
{
        USART_InitTypeDef USART_InitStructure;
        /* 第4步:配置USART参数
        - BaudRate = 115200 baud
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
        */
        USART_InitStructure.USART_BaudRate = 19200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        USART_Init(USART1, &USART_InitStructure);
        //空闲中断
        USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);
        /* 第5步:使能 USART, 配置完毕 */
        USART_Cmd(USART1, ENABLE);
        /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
        如下语句解决第1个字节无法正确发送出去的问题 */
        USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */
        USART_InitStructure.USART_BaudRate = 9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        USART_Init(USART2, &USART_InitStructure);
        USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);//开启空闲,帧错,噪声,校验错中断 
        USART_Cmd(USART2, ENABLE);
        /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
        如下语句解决第1个字节无法正确发送出去的问题 */
        USART_ClearFlag(USART2, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */
}
DMA配置:
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1
/* DMA1 Channel4 (triggered by USART1 Tx event) Config */
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SEND_DATA;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 512;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
/* Enable USART1 DMA TX request */
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, DISABLE);
/* DMA1 Channel5 (triggered by USART2 Tx event) Config */
DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_SEND_DATA;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 512;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel7, DMA_IT_TE, ENABLE);
/* Enable USART1 DMA TX request */
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel7, DISABLE);
/* DMA1 Channel5 (triggered by USART1 Rx event) Config */
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DATA;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 512;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);

/* Enable USART1 DMA RX request */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
/* DMA1 Channel6 (triggered by USART1 Rx event) Config */
DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_RECEIVE_DATA;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 512;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);
/* Enable USART2 DMA RX request */
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel6, ENABLE);
}
中断优先级配置:
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Enable the USART1 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//Enable DMA Channel4 Interrupt 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//Enable DMA Channel7 Interrupt 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*Enable DMA Channel5 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/*Enable DMA Channel6 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
数组定义,含义如题名:
u8 USART1_SEND_DATA;   
u8 USART2_SEND_DATA; 
u8 USART1_RECEIVE_DATA; 
u8 USART2_RECEIVE_DATA; 
u8 USART1_TX_Finish=1;// USART1发送完成标志量
u8 USART2_TX_Finish=1; // USART2发送完成标志量
USART1中断服务函数
void USART1_IRQHandler(void)
{
        u16 DATA_LEN;
        u16 i;
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//如果为空闲总线中断
    {
                DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
                //USART_RX_STA = USART1->SR;//先读SR,然后读DR才能清除
      //USART_RX_STA = USART1->DR;
                DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel5); 
                if(DATA_LEN > 0)
      {                        
                        while(USART1_TX_Finish==0)//等待数据传输完成才下一次
            {
                ;
            }
                        //将数据送DMA存储地址
            for(i=0;i            {
                USART1_SEND_DATA=USART1_RECEIVE_DATA;
            }
            //USART用DMA传输替代查询方式发送,克服被高优先级中断而产生丢帧现象。
            DMA_Cmd(DMA1_Channel4, DISABLE); //改变datasize前先要禁止通道工作
            DMA1_Channel4->CNDTR=DATA_LEN; //DMA1,传输数据量
            USART1_TX_Finish=0;//DMA传输开始标志量
            DMA_Cmd(DMA1_Channel4, ENABLE);                        
                }
                //DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
                DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清标志
                DMA1_Channel5->CNDTR = 512;//重装填
                DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA
                //读SR后读DR清除Idle
                i = USART1->SR;
                i = USART1->DR;
        }
        if(USART_GetITStatus(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出错
        {
                USART_ClearITPendingBit(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE);
        }
        USART_ClearITPendingBit(USART1, USART_IT_TC);
        USART_ClearITPendingBit(USART1, USART_IT_IDLE);
}
USART2中断服务函数
void USART2_IRQHandler(void)
{
        u16 DATA_LEN;
        u16 i;
        if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //如果为空闲总线中断
    {
                DMA_Cmd(DMA1_Channel6, DISABLE);//关闭DMA,防止处理其间有数据
                //USART_RX_STA = USART1->SR;//先读SR,然后读DR才能清除
      //USART_RX_STA = USART1->DR;
                DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel6); 
                if(DATA_LEN > 0)
      {                        
                        while(USART2_TX_Finish==0)//等待数据完成才下一次
            {
                ;
            }
                        //将数据送DMA存储地址
            for(i=0;i            {
                USART2_SEND_DATA=USART2_RECEIVE_DATA;
            }
            //USART用DMA传输替代查询方式发送,克服被高优先级中断而产生丢帧现象。
            DMA_Cmd(DMA1_Channel7, DISABLE); //改变datasize前先要禁止通道工作
            DMA1_Channel7->CNDTR=DATA_LEN; //DMA1,传输数据量
            USART2_TX_Finish=0;//DMA传输开始标志量
            DMA_Cmd(DMA1_Channel7, ENABLE);                        
                }
                //DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
                DMA_ClearFlag(DMA1_FLAG_GL6 | DMA1_FLAG_TC6 | DMA1_FLAG_TE6 | DMA1_FLAG_HT6);//清标志
                DMA1_Channel6->CNDTR = 512;//重装填
                DMA_Cmd(DMA1_Channel6, ENABLE);//处理完,重开DMA
                //读SR后读DR清除Idle
                i = USART2->SR;
                i = USART2->DR;
        }
        if(USART_GetITStatus(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出错
        {
                USART_ClearITPendingBit(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE);
        }
        USART_ClearITPendingBit(USART2, USART_IT_TC);
        USART_ClearITPendingBit(USART2, USART_IT_IDLE);
}
DMA1_Channel5中断服务函数
void DMA1_Channel5_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC5);
DMA_ClearITPendingBit(DMA1_IT_TE5);
DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
DMA1_Channel5->CNDTR = 580;//重装填
DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA
}
DMA1_Channel6中断服务函数
void DMA1_Channel6_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC6);
DMA_ClearITPendingBit(DMA1_IT_TE6);
DMA_Cmd(DMA1_Channel6, DISABLE);//关闭DMA,防止处理其间有数据
DMA1_Channel6->CNDTR = 580;//重装填
DMA_Cmd(DMA1_Channel6, ENABLE);//处理完,重开DMA
}
DMA1_Channel4中断服务函数
//USART1使用DMA发数据中断服务程序
void DMA1_Channel4_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC4);
DMA_ClearITPendingBit(DMA1_IT_TE4);
DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMA
USART1_TX_Finish=1;//置DMA传输完成
}
DMA1_Channel7中断服务函数
//USART2使用DMA发数据中断服务程序
void DMA1_Channel7_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC7);
DMA_ClearITPendingBit(DMA1_IT_TE7);
DMA_Cmd(DMA1_Channel7, DISABLE);//关闭DMA
USART2_TX_Finish=1;//置DMA传输完成
},全部完,但是程序在开始启动时会出现自己发几个不知道什么字符,之后一切正常。如有什么问题,请大神指教。个人认为问题不大,因为在工作的时候通过STM32访问后台或者后台访问STM32大量的间隔密的数据时没有出现问题。而如果没有使用DMA,单帧数据发收可以,多帧数据经过USART1转USART2,就收不到从USART2反馈的第二帧数据了。不一定是速度上的问题,可能是我处理顺序的问题,但是不管是巧合,还是瞎撞的,总归解决办法的就是好办法。


关键字:STM32  USART  DMA接收 引用地址:STM32实现USART+DMA接收未知长度的数据和发送

上一篇:STM32 HAL 库, 配置串口DMA接收及空闲中断
下一篇:STM32 串口采用DMA方式收发

推荐阅读最新更新时间:2024-03-16 16:05

STM32 Flash 均衡保存算法
在实际应用中,经常需要在程序运行过程中保存或读取一些数据,这些数据在工作中经常会变化,而且掉电后也不能丢失,所以需要及时地进行存储,存储这些数据常用的存储器是 EEPROM。 STM32 虽然本身不带 EEPROM,但是它支持自编程技术,可以利用内部 FLASH 来模拟 EEPROM,这样不仅简化了设计,而且降低了成本。 FLASH 的擦写次数是有限的,一般是 10W 次, FLASH 单个存储单元bit只能从1变为0,而不能从0变成1。 想要变成1,只能 page 擦除,这里的 page 表示一个擦除单位,擦除过程就是把 page 所有的位都写1,这种硬件特性决定需要一种比较高效的写 flash 算法。 总不能一
[单片机]
stm32按键 长按 短按 函数
在stm32工程中,长按和短按的代码书写, 调用的读取按键状态的底层函数。封装成的按键函数代码。下面是函数的头文件,和.c文件的代码。使用定时器来扫描按键。 #define KEY_ON 1 #define KEY_OFF 0 #define KEY_NULL 0 #define KEY_SHORT 1 #define KEY_LONG 10 #define SHORT_TIME 200 uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin) { static uint8_t key_value = KEY_NULL; static uint16_t longtim
[单片机]
stm32采用dma方式的ADC
# define M 3 #define N 10 uint16_t AD_Value ; void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; ADC_DeInit (ADC1 );//将外设adc1的全部寄存器设置为默认值 ADC_InitStructure .ADC_Mode =ADC_Mode_Independent ;//设置为独立ADC模式 ADC_InitStructure .ADC_ScanConvMode =ENABLE ;//adc工作在扫描模式 ADC_InitStructure .ADC_ContinuousConvMode =
[单片机]
STM32单片机GPIO口的工作模式解析
STM32单片机的每组IO口都有4个32位配置寄存器用于配置GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR和GPIOx_PUPDR,2个32位数据寄存器用于配置输入和输出寄存器GPIOx_IDR和GPIOx_ODR,1个32位置位复位寄存器GPIOx_BSRR,1个32位锁定寄存器GPIOx_LCKR和2个32位复用功能选择寄存器GPIOx_AFRH和GPIOx_AFRL。 GPIO的输出状态可以配置为推挽或开漏加上上拉或下拉。输出数据既可以来自输出数据寄存器,也可以由其他外围寄存器发出。每组IO口的速度都是可以配置的,可以配置为25MHz,50MHz或是100Mhz。数据输入同样也有几种模式
[单片机]
<font color='red'>STM32</font>单片机GPIO口的工作模式解析
STM32自学之SPI的DMA操作(寄存器级)
STM32自学之SPI的DMA操作(寄存器级) 一、实验目标 学会配置STM32的SPI寄存器和DMA寄存器,实现STM32的SPI1与SPI2通信功能,每次发送一字节数据,并可多次发送,如果接收的数据正确,则点亮LED灯。之后看可以利用DMA来实现什么功能~~~ 二、实验目的 加入DMA的SPI通信相对于普通SPI通信有什么好处?ST给SPI加了DMA功能出于什么目的?我觉得这是很重要的一个问题,一直边学习边想。以下是我的看法: 减少CPU负荷?我想这应该是DMA最主要的功能,可是对于SPI通信来说,其实大部分时候我们需要根据发送的指令- 目标器件的应答来决定下一个指令,所以此时CPU还是需要一直等待每次通信的结束。而且
[单片机]
<font color='red'>STM32</font>自学之SPI的<font color='red'>DMA</font>操作(寄存器级)
STM32 NVIC 中断
***************************** STM32 NVIC 中断 一、STM32 的中断分组:STM32 将中断分为 5 个组,组 0~4。该分组的设 置是由 SCB- AIRCR 寄存器的 bit10~8 来定义的。具体的分配关系如表所示: 组…,…,. bit 分配情况 …,…,…,…分配结果 0 …,…,…,…,…,…0:4 …,…,…,…0 位抢占优先级,4 位响应优先级 1 …,…,…,…,…,…1:3 …,…,…,…1 位抢占优先级,3 位响应优先级 2 …,…,…,…,…,…2:2 …,…,…,…2 位抢占优先级,2 位响应优先级 3…,…,…,…,…,…3:1…,…,…,… ,3 位抢占优
[单片机]
STM32F4 学习 day4 正点原子 第12讲 STM32 GPIO口工作原理
以上为GPIO的讲解顺序 在 开发指南第六章有简要的介绍 GPIO口 官方的参考 STM32F4中文参考手册 STM32 F407 的芯片资料 STM32f407 有7组 IO口 1.输入浮空 如果一个IO口 被配制成了浮空输入模式,那么它的 输出驱动器这部分的电路是不工作的。电平从IO口输入后先经过可以配置的上拉下拉 ,然后经过 TTL施密特触发器就会被打开,那么就可以通过输入数据寄存器读取IO口的电平。 2 输入上拉 如果被配置为输入上拉后,如上图所示的上拉电阻会被接到Vdd,输入的电平会被拉倒VDD, 之后经过TTL触发器后到输入数据寄存器,之后被CPU读取 3输入下拉 输入电平被拉低 4 模拟输入
[单片机]
STM32F4 学习 day4 正点原子 第12讲 <font color='red'>STM32</font> GPIO口工作原理
STM32单片机FSMC模块的应用
一、基本概念 1.与非总线复用的16位SRAM接口 FSMC配置 SRAM存储器和NOR闪存存储器共用相同的FSMC存储块,所用的协议依不同的存储器类型而有所不同。 控制SRAM存储器,FSMC应该具有下述功能: 使用或禁止地址/数据总线的复用功能。 选择所用的存储器类型:NOR闪存、SRAM或PSRAM。 定义外部存储器的数据总线宽度:8或16位。 使用或关闭扩展模式:扩展模式用于访问那些具有不同读写操作时序的存储器。 正如配置NOR闪存存储器一样,用户必须按照SRAM存储器的数据手册给出的时序数据,计算和设置下列参数: ADDSET:地址建立时间 ADDHOLD:地址保持时间 DATAST:数据建立时间 二、例程 1.
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved