S3C2416裸机开发系列十九_Fatfs下播放录音wav音频文件

发布者:晴天7777最新更新时间:2016-12-12 来源: eefocus关键字:S3C2416  裸机开发  播放录音  音频文件 手机看文章 扫描二维码
随时随地手机看文章

 

S3C2416裸机开发系列十九_Fatfs下播放录音wav音频文件

标签: wavfatfs音频播放s3c2416sd驱动

2014-06-11 09:55 1938人阅读 评论(0) 收藏 举报

 分类:

s3c2416裸机开发(24) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[+]

S3C2416裸机开发系列十九

Fatfs下播放录音wav音频文件

象棋小子    1048272975

对于多媒体资源,一般都是以文件的形式存储在固化存储器中。Fatfs所支持的fat32为windows支持的文件系统,因此在嵌入式系统中采用Fatfs文件系统可极大地扩展系统的应用。例如,把计算机上图片,音频,视频,文本等资源直接拷贝到嵌入式系统中的固化存储器中,在系统中即可直接应用这些资源。把嵌入式系统中录制的音频、视频直接保存成一定的格式,在计算机上可直接播放处理,把传感器采集的数据保存成txt或dat文件,在计算机上通过处理生成数据曲线分析等。笔者此处就wav音频文件的播放与录音进行简单的介绍。

1. wav音频格式

Wave是录音时用的标准windows文件格式,文件扩展名为”.wav”,数据本身的格式为PCM或压缩型,它是由微软与IBM联合开发的用于音频数字存储的标准,采用RIFF文件格式结构。

RIFF全称资源互换文件格式,是windows下大部分多媒体文件遵循的一种文件结构,除了本文所说的波形格式数据(.wav),采用RIFF格式结构的文件还有音频视频交错格式(.avi)、位图格式(.rdi)、MIDI格式(.rmi)、调色板格式(.pal)、多媒体电影(.rmn)、动画光标(.ani)。

RIFF结构的基本单元为chunk,它的结构如下:

struct  chunk {

unsignedint  id; /*  块标志 */

unsignedint  size; /* 块大小 */

unsigned chardata[size]; /* 块内容 */

}

Id为4个ascii字符组成,用来识别块中所包含的数据,如”RIFF”、”WAV ”、”data”、”fmt ”等;size是存储在data域中数据的长度,不包括id与size域的大小;data[size]为该块保存的数据,以字为单位排列。

wav音频文件作为RIFF结构,其由若干个chunk组成,按照在文件中的位置包括:RIFF chunk,fmt chunk,fact chunk(可选),data chunk。所有RIFF结构文件均会首先包含RIFF chunk,并指明RIFF类型,此处为”WAVE”。对于wav文件,在fmt chunk中指明音频文件的信息,例如采样位数、采样频率、声道数、编码方式等。对于压缩型wav音频,还会有一个fact chunk,用以指明解压后音频数据的大小,对于PCM非压缩wav文件,并没有该chunk。音频数据保存在data chunk中,根据fmt chunk中指明的声道数以及采样位数,wav音频数据存放形式有不同的方式。

一个PCM格式的wav结构定义Wav.h如下:

#ifndef __WAV_H__

#define __WAV_H__

#ifdef __cplusplus

extern "C" {

#endif

   

//资源互换文件格式RIFF,树状结构,基本单位是chunk,整个文件由chunk构成

typedef struct RIFF_HEADER {

    char Riff_ID[4];

    unsigned int Riff_Size;//记录整个RIFF文件的大小,除ID和Size这两个变量

    char Riff_Format[4];

} RIFF_HEADER;

 

typedef struct WAVE_FORMAT {

    unsigned short FormatTag; //声音的格式代号

    unsigned short Channels; //声音通道

    unsigned int SamplesPerSec; //采样率

    unsigned int AvgBytesPerSec; //=采样率*区块对其单位

    unsigned short BlockAlign; //区块对其单位=每个取样所需位数*声音通道/8

    unsigned short BitsPerSample; //每个取样所需位数

} WAVE_FORMAT;

 

typedef struct FMT_CHUNK {

    char Fmt_ID[4];

    unsigned int Fmt_Size;//记录fmt的大小

    WAVE_FORMAT WaveFormat;

} FMT_CHUNK;

 

typedef struct DATA_CHUNK {

    char Data_ID[4];

    unsigned int Data_Size;//记录data区的大小

} DATA_CHUNK;

 

typedef struct WAVE_HEADER {

    RIFF_HEADER   RiffHeader;

    FMT_CHUNK   FmtChunk;

    DATA_CHUNK  DataChunk;

} WAVE_HEADER;

 

#ifdef __cplusplus

}

#endif

#endif /*__WAV_H__*/

根据以上的wav结构定义,一个录音文件的wav文件头可如下定义:

static WAVE_HEADER RecorderWaveHeader = {

    'R', 'I', 'F', 'F',

    sizeof(WAVE_HEADER) - 8,//整个wave文件大小,初始化值

    'W', 'A', 'V', 'E',

    'f', 'm', 't', ' ',

    sizeof(FMT_CHUNK) - 8,

    1,//编码方式,线性PCM编码

    1,//单声道

    10000,//采样率为10k

    20000,//每个采样2个字节

    2,//每个采样2个字节

    16,//每个采样需16位

    'd', 'a', 't', 'a',

    0, //data长度初始化为0

};

2. wav音频文件的播放或录音

sd卡由于其可插拔、灵活性好,通常应用于设备的扩展存储应用。计算机上wav音频等文件可轻易地拷贝到fat32格式的sd卡上,在嵌入式系统中要使用sd卡,首先需实现sd卡驱动,这在前面的章节有详细的介绍,此处不再详述。fat32文件的读写还需要相应文件系统的接口支持,此处选用Fatfs,对于不同的嵌入式系统,这是需要移植的部分,关于s3c2416下Fatfs文件系统的移植在前面章节有详细的介绍,此处不再详述。从wav文件读出音频数据后(播放),还需要把音频数据传输给声卡,声卡还原出声音模拟信号,即可听到声音。音频数据的处理需要用到音频编解码器,数据的传输也有一定的音频总线要求,因此还需要音频驱动的实现,这部分在前面的章节有详细的介绍,此处不再详述。

3. 应用实例

工程中利用串口对耳机音量进行加大、调小,对Mic录音进行灵敏度的调节,通过串口输入进行播放wav音频或开始录音。播放时实时显示播放进度并可按下’s’后停止播放,录音时实时显示录音wav文件的大小并可按下’s’后停止录音。

main.c的内容如下:

#include"s3c2416.h"

#include"UART0.h"

#include"ff.h"

#include"diskio.h"

#include "RTC.h"

#include"Wav.h"

#include"IIS.h"

#include"IIC.h"

#include"WM8960.h"

 

staticWAVE_HEADER RecorderWaveHeader = {

    'R', 'I', 'F', 'F',

    sizeof(WAVE_HEADER) - 8,//整个wave文件大小

    'W', 'A', 'V', 'E',

    'f', 'm', 't', ' ',

    sizeof(FMT_CHUNK) - 8,

    1,//编码方式,线性PCM编码

    1,//单声道

    10000,//采样率为10k

    20000,//每个采样2个字节

    2,//每个采样2个字节

    16,//每个采样需16位

    'd', 'a', 't', 'a',

    0, //data长度初始化为0

};

 

// 音频数据缓存20KB

unsigned charAudioBuffer[20*1024];

 

int main()

{

    FATFS fs;

    FIL file;

    FRESULT Res;

    unsigned int i;

    unsigned int BufferLen;

    unsigned char *pData;

    WAVE_HEADER WaveHeader;

    int ByteWrite, ByteRead;

    unsigned char State;

    unsigned char VolumeLevel;

    unsigned short Command;

    const char Path1[] = "test.wav";

    const char Path2[] = "1.wav";

    char FilePath[256];

   

    unsigned int Size = 0;

    unsigned int AudioSize = 0;

    unsigned int TotalSize = 0;

   

    RTC_Time Time = {

        2014, 5, 22, 23, 00, 0, 5

    }; 

   

    RTC_Init(&Time); // RTC初始化

    Uart0_Init(); // 串口初始化

    IIC_Init(); //IIC初始化,音频芯片控制

    IIS_Init(); // IIS音频接口初始化

    WM8960_Init(); // 音频编解码器初始化

    RTC_GetTime(&Time); // 显示RTC时间

    Uart0_Printf("Time: %4d/%02d/%02d%02d:%02d:%02d\r\n", Time.Year,

                Time.Month, Time.Day, Time.Hour,Time.Min, Time.Sec);  

    f_mount(&fs, "" , 0);          

    ByteRead = 0;

    pData = (unsigned char *)0;

    for (i=0; i

        FilePath[i] = Path1[i];

    }

    State = 1; // 进入播放test.wav状态

    while(1) {

    switch (State) {

    case 0: // 操作选择

        WM8960_HeadphoneStop();

        WM8960_RecorderStop();

        IIS_TxPause();

        IIS_RxPause();

        Uart0_SendString("\r\nSelect:\r\n"

                         "0: Play test.wav\r\n"

                         "1: Play recording file\r\n"

                         "2: Start recorder\r\n"

                         "3: Recorder volume up\r\n"

                         "4: Recorder volume down\r\n"

                         "5: Player volume up\r\n"

                         "6: Player volume down\r\n"

                        );

        while(State == 0) {

            // 等待串口选择操作,阻塞型

            Command = Uart0_ReceiveByte();

            switch (Command) {

            case '0': // 播放test.wav

                for (i=0; i

                    FilePath[i] = Path1[i];

                }

                State = 1; // 转到开始播放wav状态

                break;

            case '1': // 播放录音wav

                for (i=0; i

                    FilePath[i] = Path2[i];

                }

                State = 1; // 转到开始播放wav状态 

                break;

            case '2':

                State = 3;  // 转到开始录音状态    

                break;

            case '3': // Mic灵敏度增加

                VolumeLevel = WM8960_RecorderVolume(VolumeUp);

                Uart0_Printf("Recordervolume %d%%\r\n", VolumeLevel);

                break;

            case '4': // Mic灵敏度减小

                VolumeLevel =WM8960_RecorderVolume(VolumeDown);

                Uart0_Printf("Recorder volume%d%%\r\n", VolumeLevel);

                break;

            case '5': // 耳机音量增加

                VolumeLevel =WM8960_HeadphoneVolume(VolumeUp);

                Uart0_Printf("Player volume%d%%\r\n", VolumeLevel);                       

                break;

            case '6': // 耳机音量降低

                VolumeLevel =WM8960_HeadphoneVolume(VolumeDown);

                Uart0_Printf("Player volume%d%%\r\n", VolumeLevel);

                break;             

            default:

                break; 

            }

        }

        Uart0_SendString("\r\n");

        break;

 

    case 1: // 开始播放音频

        // 打开wav音频文件

        Res = f_open(&file, FilePath, FA_READ | FA_OPEN_EXISTING);

        if (Res != RES_OK) {

            Uart0_Printf("Open %s failed\r\n",FilePath);

            State = 0; // 进入到操作选择界面

        } else {

            // 读取wav音频文件头,获得音频采样率,位数,声道数信息

            Res = f_read(&file, (unsignedchar *)&WaveHeader,

                    sizeof(WAVE_HEADER),(unsigned int *)&ByteRead);

            if (Res != RES_OK) {

                f_close(&file);

                Uart0_Printf("Read wavheader error\r\n");

                State = 0; // 进入到操作选择界面

            } else {

                // 读取一小段音频数据到缓存中

                Res = f_read(&file,(unsigned int *)AudioBuffer,

                    sizeof(AudioBuffer), (unsignedint *)&ByteRead);

                if (Res != RES_OK) {

                    Uart0_Printf("Read wavdata error\r\n");   

                    f_close(&file);

                    State = 0; // 进入到操作选择界面

                } else {

                    if (ByteRead

                        // 已播放到文件的结尾,重定位到音频文件的开始

                        Res = f_lseek(&file,sizeof(WAVE_HEADER));

                        if (Res != RES_OK) {   

                            Uart0_Printf("f_lseek error\r\n");

                            f_close(&file);

                            State= 0; // 进入到操作选择界面

                            break;

                        }

                    }

                    // 根据wav文件头的音频信息初始化音频驱动的播放参数

                IIS_TxInit(WaveHeader.FmtChunk.WaveFormat.SamplesPerSec,

                    WaveHeader.FmtChunk.WaveFormat.BitsPerSample,

WaveHeader.FmtChunk.WaveFormat.Channels);

                    // wav文件的总文件大小,bytes计

                    TotalSize =WaveHeader.RiffHeader.Riff_Size;

                    pData = AudioBuffer; // 播放指向音频缓存区

                    // 把pData指向的数据写入音频缓存,最大允许写入

                    // ByteRead字节,返回实际写入到音频缓存的字节数

                    BufferLen = IIS_WriteBuffer(pData,ByteRead);

                    ByteRead -= BufferLen; // 数据剩余字节数

                    pData += BufferLen; // 数据下一次开始写入的位置

                    Size = BufferLen; // 播放的长度

                    AudioSize = 0; // 已播放的音频长度

                    WM8960_HeadphoneStart(); // 打开耳机播放通道

                    IIS_TxStart(); // IIS开始传输音频播放

                    State= 2; // 转入正在播放音频状态

                    Uart0_SendString("PlayingMusic, press 's' to stop"

                                "playing at any time\r\n");

                    Uart0_SendString("Playbackprogress: 00.0%");

                }

            }

        }  

        break; 

       

    case 2:// 正在播放音频

        if (ByteRead > 0) {    

        // 返回值的高8位不为0,说明低8位键值有效,查询是否有串口输入,非阻塞

            Command = Uart0_Peek();

            if (Command & (0xff<<8)) {// 有按键按下

                if ((Command & 0xff) == 's'){ // 按下了's'

                    f_close(&file);

                    State = 0; // 返回到操作选择界面

                    break;

                }

            }

            if (Size > 20*1024) { // 播放了20k大小的音频数据

                AudioSize += (Size>>10);// 累计己播放的总音频数据大小(KB)

                Size = 0;

                Uart0_SendString("\b\b\b\b\b");

                // 显示播放进度的百分比

                Uart0_Printf("%02d.%d%%",(AudioSize*100)/(TotalSize>>10),

 ((AudioSize*100)%(TotalSize>>10))*10/(TotalSize>>10));

            }

            // 连续写入音频数据到音频缓存中,实现连续播放

            BufferLen = IIS_WriteBuffer(pData,ByteRead);

            ByteRead -= BufferLen; // 数据剩余字节数

            pData += BufferLen; // 数据下一次开始写入的位置

            Size += BufferLen;

        } else { // 播放完缓存中的音频数据,再从sd卡加载下一段音频数据

            // 一段音频数据播放完后,从sd卡中加载下一段数据

            Res = f_read(&file, (unsignedchar *)AudioBuffer,

                    sizeof(AudioBuffer),(unsigned int *)&ByteRead);

            if (Res != RES_OK) {

                Uart0_Printf("Read wav dataerror\r\n");   

                f_close(&file);

                State = 0; // 进入到操作选择界面

            } else {       

                pData = AudioBuffer; // 重定位到数据首位置

                if (ByteRead

                    // 到文件结尾,文件重定位到开头,重播放

                    Uart0_Printf("\r\n");

                    Uart0_Printf("replay%s\r\n", FilePath);

                    Uart0_SendString("Playbackprogress: 00.0%");

                    Size = 0;

                    AudioSize = 0;

                    Res = f_lseek(&file,sizeof(WAVE_HEADER));

                    if (Res != RES_OK) {   

                        Uart0_Printf("Replayaudio error\r\n");

                        f_close(&file);

                        State = 0; // 进入到操作选择界面

                    }

                }

            }

        }

        break;

       

    case 3: // 开始录音

        // 创建录音保存1.wav文件

        Res = f_open(&file, "1.wav",FA_WRITE | FA_CREATE_ALWAYS);

        if (Res != RES_OK) {       

            Uart0_Printf("Create 1.wavfailed\r\n");

            State = 0; // 进入到操作选择界面

        } else {

            // 写入wav文件头

            Res = f_write(&file, (unsignedchar *)&RecorderWaveHeader,

                    sizeof(WAVE_HEADER), (unsignedint *)&ByteWrite);

            if (Res != RES_OK) {

                f_close(&file);

                Uart0_Printf("Write wavheader error\r\n");

                State = 0; // 进入到操作选择界面

            } else {

            // 初始化录音参数,采样率,采样位数,声道数

            IIS_RxInit(RecorderWaveHeader.FmtChunk.WaveFormat.SamplesPerSec,

RecorderWaveHeader.FmtChunk.WaveFormat.BitsPerSample,

RecorderWaveHeader.FmtChunk.WaveFormat.Channels);

                Size = 0;

                AudioSize = 0; // 总录音文件大小初始化0

                pData = AudioBuffer; // 指向录音缓存区

                ByteWrite = sizeof(AudioBuffer);// 一段音频缓存的大小

                WM8960_RecorderStart(); //WM8960打开录音通道

                IIS_RxStart(); // IIS开始接收录音数据

                State = 4; // 转到正在录音状态     

                Uart0_SendString("Recording,press 's' to stop recording"

                           "at any time\r\n");

                Uart0_SendString("Recording(KB):       ");

            }

        }

        break;

           

    case 4:// 正在录音

        if (ByteWrite > 0) {

        // 返回值的高8位不为0,说明低8位键值有效,查询是否有串口输入,非阻塞

            Command = Uart0_Peek();

            if (Command & (0xff<<8)) {// 有按键按下

                if ((Command & 0xff) == 's'){ // 按下了's'

                    // 停止录音,更改wav文件头文件大小

                    f_lseek(&file, 0); // 定位到文件头

                    // 数据大小改为录音的音频大小

                    RecorderWaveHeader.DataChunk.Data_Size= AudioSize;

                    // RIFF大小改为整个文件文件的大小

                    RecorderWaveHeader.RiffHeader.Riff_Size=

(sizeof(WAVE_HEADER)-8) + AudioSize;

                    // 更改wav文件头信息

                    f_write(&file, (unsignedchar *)&RecorderWaveHeader,

                    sizeof(WAVE_HEADER),(unsigned int *)&ByteWrite);

                    f_close(&file);

                    State = 0; // 进入到操作选择界面

                    break;

                }

            }          

            if (Size > 20*1024) { // 记录了20k大小的音频数据

                AudioSize += Size; // 累计己播放的总音频数据大小

                Size = 0;

                Uart0_SendString("\b\b\b\b\b\b");

                // 显示已录音的文件大小

                Uart0_Printf("%6d",(AudioSize>>10));

            }

            // 从音频缓存中读取录音数据到pData中,最大允许读取ByteWrite

            // 字节大小,返回实际从音频缓存中读取的字节数

            BufferLen = IIS_ReadBuffer(pData,ByteWrite);

            ByteWrite -= BufferLen; // 剩余内存空间字节数

            pData += BufferLen; // 下一位读开始存入的内存位置  

            Size += BufferLen;

        } else { // 缓存已满,写入缓存数据到sd卡中

            Res = f_write(&file, (unsignedchar *)&AudioBuffer,

                    sizeof(AudioBuffer),(unsigned int *)&ByteWrite);

            if (Res != RES_OK) {

                f_close(&file);

                Uart0_Printf("Write 1.waverror\r\n");

                State = 0; // 进入到操作选择界面

} else {

                pData = AudioBuffer;

                ByteWrite = sizeof(AudioBuffer);

            }

        }

        break;

 

    default:

        break;

    }

}

}

 


4. 附录

通过Fatfs的api函数,可以轻易读写windows下常见格式文件,这和windows/Linux下操作文件差异不大。播放对wav音频文件无特殊要求,可任意采样率、采样位数、单/双声道,插上耳机即能听到声音,录制wav音频对采样率、采样位数、声道数、录制长度等均没有任何限制,录制好的wav音频文件可直接在计算机上播放。虽然wav格式音频文件较占用存储空间,但其是无损的,音质在相同码率下远好于mp3等有损压缩音频文件。

Wav_GCC.rar,GCC下wav音频文件播放与录制工程,可直接make。

http://pan.baidu.com/s/1c05s2cg

Wav_MDK.rar,MDK下wav音频文件播放与录制工程

http://pan.baidu.com/s/1i33guiD

test.wav,wav播放测试音频文件,11.025k采样率、16位、单声道音乐,可通过音频格式转换软件生成wav音频文件。

http://pan.baidu.com/s/1eQzOErg


关键字:S3C2416  裸机开发  播放录音  音频文件 引用地址:S3C2416裸机开发系列十九_Fatfs下播放录音wav音频文件

上一篇:S3C2416裸机开发系列二十_Libjpeg的移植
下一篇:S3C2416裸机开发系列十八_音频驱动实现(2)

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

ARM裸机程序开发——按键控制LED灯
这几天将TQ2440上的IO控制引脚学习了一下,了解了一下关于引脚的一些寄存器的配置,熟悉了一下写ARM裸机程序的流程,写一下自己学到的东西。 ★程序启动初始化 ◇关闭看门狗 有一个专门的寄存器来控制看门狗,看门狗的作用就是在一定的时间内会重新启动系统,这里我们只是写一个简单的逻辑程序用不到看门狗 ,将其关掉。设置WTCON寄存器,将其第5位置0,就可以禁用看门狗 ◇设置栈指针 C语言中设置的变量,以及调用的函数等信息都会被存放在栈中,因此栈指针必须要设置 ◇调用main函数 main函数中设置了关于IO寄存器的一些设置操作 ★TQ2440硬件相关 硬件主要涉及到LED灯与GPIO,按键与GPIO之间的连接 ◇LED灯硬件
[单片机]
ARM裸机开发bootloader我是bootloader设计师
一、bootloader设计蓝图 1、什么是bootloader 如果说系统内核是航天飞机的话,那么bootloader就是助推器,它带动了内核。在内核启动之前它要做许多硬件的初始化操作,来适合系统的安全启动。 2、bootloader设计方法-模仿 90%的设计从模仿开始,模仿加入自己的想法就是设计。bootloader的模仿我们一般会参照行业老大uboot。 3、uboot简介 uboot可以支持多种嵌入式cpu,例如X86、ARM、MIPS 还可以支持多种嵌入式操作系统,例如wince、linux、vxworks、QNX uboot分为自主模式和开发模式:自主模式下,uboot的运行不需要人的参与,这往往也是产品
[单片机]
ARM<font color='red'>裸机</font><font color='red'>开发</font>bootloader我是bootloader设计师
ARM裸机开发bootloader—点亮LED灯
1、编写LED驱动的流程 a、原理图分析 b、芯片手册 c、思维导图 d、编写代码 2、为什么要点亮led 在嵌入式软件(bootloader、kernel)开发初期,由于串口等硬件尚未进行初始化,所以可以用来调试的手段很有限。这时通常运用点亮led作为调试的重要手段。也就是说不断改动led点亮程序的位置,来查看那段代码出现了问题,然后进行针对性的修改。 下面我用6410为例进行点亮led的介绍,其他的如2440和210流程相似。 a、原理图分析 从led的原理图我们可以看到,nLED_*低电平有效,也就是对应的s3c6410GPK4-7低电平,这个时候要引出一个概念:GPIO 什么是GPIO GP
[单片机]
ARM<font color='red'>裸机</font><font color='red'>开发</font>bootloader—点亮LED灯
一个低级的S3c2416 wince SD eboot汇编错误
C:WINCE500PLATFORMSMDK2416srcbootloaderEboot.Whimorystartup.s(332) : error A0034: undefined symbol: _undef_loc_label_ 不仔细看还真不知道是啥,后来看看逻辑就应该知道。是%B20 的20 有问题,代码根本没有20的标号。并且从逻辑来看,这个应该是100 才对。
[单片机]
jz2440裸机开发与分析:内存控制器4之SDRAM设置
LDR R0,=0X30000000 ➡CPU发给内存控制器:①发出nGCS6;②根据(SDRAM)类型拆分地址:a,BANK地址,b,行地址, c,列地址 ;③读数据 LDR R1, 问题:如何拆分?行地址几条?列地址几条? 2440内存控制器设置 1、BWSCON寄存器配置=0x22000000 2、BANKCON6寄存器配置 3、REFRESH刷新寄存器配置 4、BANHSIZE配置 5、MRSRB6 SDRAM中有一个MR寄存器(含有CL),用来确定列地址到发出数据中间间隔的时间,而2440内的MRSRB6寄存器也有一个CL,2440根据内部CL设定的值,再通过发送数据去确定SDRAM中的C
[单片机]
jz2440<font color='red'>裸机</font><font color='red'>开发</font>与分析:内存控制器4之SDRAM设置
STM32裸机开发—外部中断
a. 初始化IO口作为输入 这一步需要设置你要作为外部中断输入的IO口的状态,可以设置为上拉/下拉输入,也可以设置为浮空输入,但浮空的时候外部硬件一定要上拉或下拉。否则可能导致中断不停地被触发。在干扰较大的地方,就算使用了上拉/下拉,也建议在外部硬件上设置上拉/下拉,这样可以在一定程度上防止外部干扰带来的影响。 *RCC_APB2ENR=0x00000019;//打开portb和portc的时钟和复用时钟 *PORTA_CRL=0x44444844;//设置PA2口为上拉/下拉输入模式 由于还需要驱动液晶屏所以同时打开了PORTB和PORTC的时钟。 b. 开启IO口复用时钟,设置IO口与中断线的映射关系
[单片机]
STM32<font color='red'>裸机</font><font color='red'>开发</font>—外部中断
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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