camera中设置界面初探

本文详细探讨了相机设置界面的构建与实现过程,包括如何根据不同设备状态展示相应的设置选项,以及如何优化用户交互体验。重点介绍了初始化设置、显示设置、以及根据不同使用场景动态调整界面布局的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在SettingManager中

    @Override
    protected View getView() {
        View view = inflate(R.layout.setting_indicator);
        mIndicator = (RotateImageView) view.findViewById(R.id.<span style="color:#FF6666;">setting_indicator</span>);
        mIndicator.setOnClickListener(this);
        return view;
    }
看下
<span style="color:#FF6666;">setting_indicator.xml这个文件</span>
<?xml version="1.0" encoding="utf-8"?>
<com.android.camera.ui.RotateImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/setting_indicator"
    style="@style/SettingIndicator"
    android:scaleType="center"
    android:clickable="true"
    android:focusable="true"
    android:padding="10dip"
    android:background="@drawable/bg_pressed"
    android:src="@drawable/<span style="color:#FF6666;">ic_setting_normal" //这个也就设置的那个图标</span>
    android:contentDescription="@string/accessibility_second_level_indicators"
    />
这里也就简单带过了,<img alt="大笑" src="http://static.blog.youkuaiyun.com/xheditor/xheditor_emot/default/laugh.gif" />想要记录的更细些
看下其中的onclick事件,注意到<span style="color:#FF6666;">showSetting()</span>方法
<pre name="code" class="java">    @Override
    public void onClick(View view) {
        if (view == mIndicator) {
            if (!mShowingContainer) {
               <span style="color:#FF6666;"> showSetting();</span>
            } else {
                collapse(true);
            }
        }
    }

 

那么看下这个方法:

    public void showSetting() {
        Log.i(TAG, "showSetting() mShowingContainer=" + mShowingContainer
                + ", getContext().isFullScreen()=" + getContext().isFullScreen());
        if (getContext().isFullScreen()) {
            if (!mShowingContainer && getContext().getCameraAppUI().isNormalViewState()) {
                mMainHandler.removeMessages(MSG_REMOVE_SETTING);
                mShowingContainer = true;
                mListener.onSettingContainerShowing(mShowingContainer);
                <span style="color:#FF0000;">initializeSettings();</span>
                refresh();
                highlightCurrentSetting(mPager.getCurrentItem());
                mSettingLayout.setVisibility(View.VISIBLE);
                if (mSettingLayout.getParent() == null) {
                    getContext().addView(mSettingLayout, SETTING_PAGE_LAYER);
                }
                getContext().getCameraAppUI().setViewState(ViewState.VIEW_STATE_SETTING);
                getContext().setSwipingEnabled(false);
                startFadeInAnimation(mSettingLayout);
                mIndicator.setImageResource(R.drawable.ic_setting_focus);
            }
            setChildrenClickable(true);
        }
    
<span style="color:#FF0000;">initializeSettings()方法:
</span><pre name="code" class="java"> <span style="color:#333333;">private void initializeSettings(){
        if (mSettingLayout == null && mSettingController.getPreferenceGroup() != null) {
            mSettingLayout = (ViewGroup) getContext().inflate(R.<span style="color:#FF6666;">layout.setting_containe</span>r,
                    SETTING_PAGE_LAYER);
            <span style="color:#FF6666;">mTabHost</span> = (TabHost) mSettingLayout.findViewById(R.id.tab_title);
            mTabHost.setup();
            
            // For tablet
            int settingKeys[] = SettingConstants.SETTING_GROUP_COMMON_FOR_TAB;
            if (FeatureSwitcher.isSubSettingEnabled()) {
                settingKeys = SettingConstants.SETTING_GROUP_MAIN_COMMON_FOR_TAB;
            } else if (FeatureSwitcher.isLomoEffectEnabled() && getContext().isNonePickIntent()) {
                settingKeys = SettingConstants.SETTING_GROUP_COMMON_FOR_LOMOEFFECT;
            }
            List<Holder> list = new ArrayList<Holder>();
            if (getContext().isNonePickIntent() || getContext().isStereoMode()) {
                if (FeatureSwitcher.isPrioritizePreviewSize()) {
                    list.add(new Holder(TAB_INDICATOR_KEY_PREVIEW,
                            R.drawable.ic_tab_common_setting,
                            SettingConstants.SETTING_GROUP_COMMON_FOR_TAB_PREVIEW));
                    list.add(new Holder(TAB_INDICATOR_KEY_COMMON, R.drawable.ic_tab_common_setting,
                            settingKeys));
                    list.add(new Holder(TAB_INDICATOR_KEY_CAMERA, R.drawable.ic_tab_camera_setting,
                            SettingConstants.SETTING_GROUP_CAMERA_FOR_TAB_NO_PREVIEW));
                    list.add(new Holder(TAB_INDICATOR_KEY_VIDEO, R.drawable.ic_tab_video_setting,
                            SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB_NO_PREVIEW));
                } else if (getContext().isStereoMode()) {
                    list.add(new Holder(TAB_INDICATOR_KEY_COMMON, R.drawable.ic_tab_common_setting,
                            settingKeys));
                    list.add(new Holder(TAB_INDICATOR_KEY_CAMERA, R.drawable.ic_tab_camera_setting,
                            SettingConstants.SETTING_GROUP_CAMERA_3D_FOR_TAB));
                    list.add(new Holder(TAB_INDICATOR_KEY_VIDEO, R.drawable.ic_tab_video_setting,
                            SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB));
                } else {
/**
      接下来就是初始化这个tabHost的东西了!
        初始化settingsKey就是设置界面的各个item对应的keyId
        list中存放的就是tabHost对应的标题,以及tab项中的内容,这时有三个页面,
        settingKesys与后面的SettingConstants.SETTING_GROUP_CAMERA_FRO_TAB,SettingContants.GROUP_VIDEO_FOR_TAB已经都初始化了
      对应的静态整型常量,也就是之后perference中key对应的id
*/

 <span style="color:#FF0000;">                   list.add(new Holder(TAB_INDICATOR_KEY_COMMON, R.drawable.ic_tab_common_setting,
                            settingKeys));
                    list.add(new Holder(TAB_INDICATOR_KEY_CAMERA, R.drawable.ic_tab_camera_setting,
                            SettingConstants.SETTING_GROUP_CAMERA_FOR_TAB));
                    list.add(new Holder(TAB_INDICATOR_KEY_VIDEO, R.drawable.ic_tab_video_setting,
                            SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB));</span>
                }
            } else { // pick case has no video quality
                if (FeatureSwitcher.isPrioritizePreviewSize()) {
                    if (getContext().isImageCaptureIntent()) {
                        list.add(new Holder(TAB_INDICATOR_KEY_PREVIEW,
                                R.drawable.ic_tab_common_setting,
                                SettingConstants.SETTING_GROUP_COMMON_FOR_TAB_PREVIEW));
                        list.add(new Holder(TAB_INDICATOR_KEY_COMMON,
                                R.drawable.ic_tab_common_setting, settingKeys));
                        list.add(new Holder(TAB_INDICATOR_KEY_CAMERA,
                                R.drawable.ic_tab_camera_setting,
                                SettingConstants.SETTING_GROUP_CAMERA_FOR_TAB_NO_PREVIEW));
                    } else {
                        list.add(new Holder(TAB_INDICATOR_KEY_COMMON,
                                R.drawable.ic_tab_common_setting, settingKeys));
                        list.add(new Holder(TAB_INDICATOR_KEY_VIDEO,
                                R.drawable.ic_tab_video_setting,
                                SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB_NO_PREVIEW));
                    }
                } else {
                    list.add(new Holder(TAB_INDICATOR_KEY_COMMON, R.drawable.ic_tab_common_setting,
                            settingKeys));
                    if (getContext().isImageCaptureIntent()) {
                        list.add(new Holder(TAB_INDICATOR_KEY_CAMERA,
                                R.drawable.ic_tab_camera_setting,
                                SettingConstants.SETTING_GROUP_CAMERA_FOR_TAB));
                    } else {
                        list.add(new Holder(TAB_INDICATOR_KEY_VIDEO,
                                R.drawable.ic_tab_video_setting,
                                SettingConstants.SETTING_GROUP_VIDEO_FOR_TAB_NO_PREVIEW));
                    }
                }
            }
            /**
                     接下来就是对tabHost设置tab页面了

           */ int size = list.size();
            List<SettingListLayout> pageViews = new ArrayList<SettingListLayout>();
            for (int i = 0; i < size; i++) {
                Holder holder = list.get(i);
                // new page view
                SettingListLayout pageView = (SettingListLayout) getContext().inflate(
                        R.layout.setting_list_layout, SETTING_PAGE_LAYER);
                ArrayList<ListPreference> listItems = new ArrayList<ListPreference>();
                pageView.initialize(getListPreferences(holder.mSettingKeys, i == 0));
                pageViews.add(pageView);
                // new indicator view
                ImageView indicatorView = new ImageView(getContext());
                if (indicatorView != null) {
                    indicatorView.setBackgroundResource(R.drawable.bg_tab_title);
                    indicatorView.setImageResource(holder.mIndicatorIconRes);
                    indicatorView.setScaleType(ScaleType.CENTER);
                }
                mTabHost.addTab(mTabHost.newTabSpec(holder.mIndicatorKey)
                        .setIndicator(indicatorView).setContent(android.R.id.tabcontent));
            }
            
            mAdapter = new MyPagerAdapter(pageViews);
            mPager = (ViewPager) mSettingLayout.findViewById(R.id.pager);
            mPager.setAdapter(mAdapter);
            mPager.setOnPageChangeListener(mAdapter);
            mTabHost.setOnTabChangedListener(this);
        }
        Util.setOrientation(mSettingLayout, getOrientation(), false);
    }</span>



 这时候的size为3,那么进入for循环,获得每个封装好的Holder对象,其中包含了标题的信息以及页面的所有item的keyId信息。pageVIew解析setting_list_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<com.android.camera.ui.SettingListLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:splitMotionEvents="false">
    <ListView android:id="@+id/<span style="color:#FF6666;">settingList</span>"
        style="@style/SettingItemList"
        android:descendantFocusability="blocksDescendants"
        android:layout_gravity="top" 
        android:splitMotionEvents="false"/>
</com.android.camera.ui.SettingListLayout>


 其实就是装在每页的布局罢了,每页面都是一个listview的布局
        这时pageView.initialize初始化listview
        先看getListPrefenrences方法,参数中holder.mSettingKeys就是之前初始化的settigKeys也就是页面中item的keyId

 

  private ArrayList<ListPreference> getListPreferences(int[] keys, boolean addrestore) {
        ArrayList<ListPreference> listItems = new ArrayList<ListPreference>();
        for (int i = 0; i < keys.length; i++) {
            String key = SettingConstants.getSettingKey(keys[i]);
            ListPreference pref = mSettingController.getListPreference(key);
            if(pref != null && pref.isShowInSetting()) {
                if (SettingConstants.KEY_VIDEO_QUALITY.equals(key)) {
                    if (!("on".equals(mSettingController
                            .getSettingValue(SettingConstants.KEY_SLOW_MOTION)))) {
                        listItems.add(pref);
                    }
                } else {
                    listItems.add(pref);
                }
                
            }
        }
        
        if (addrestore) {
            listItems.add(null);
        }
        return listItems;
    }
    

看到这个方法,其中就有settingContants.getSettingKey(int  settingId)看一下如何获得

SettingConstants.java

 public static String getSettingKey(int settingId) {
        return <span style="color:#FF6666;">KEYS_FOR_SETTING</span>[settingId];
    }
看到KEYS_FOR_SETTING这个静态数组,原来这个数组是个静态初始化的数组,通过静态代码块早已初始化了,看下初始化的内容,我们就恍然了
   // setting key and index
    public static final String[] KEYS_FOR_SETTING = new String[SETTING_COUNT];
    
    static {
        KEYS_FOR_SETTING[ROW_SETTING_FLASH]                 = KEY_FLASH;
        KEYS_FOR_SETTING[ROW_SETTING_DUAL_CAMERA]           = KEY_CAMERA_ID;//need recheck
        KEYS_FOR_SETTING[ROW_SETTING_EXPOSURE]              = KEY_EXPOSURE;
        KEYS_FOR_SETTING[ROW_SETTING_SCENCE_MODE]           = KEY_SCENE_MODE;
        KEYS_FOR_SETTING[ROW_SETTING_WHITE_BALANCE]         = KEY_WHITE_BALANCE;
        KEYS_FOR_SETTING[ROW_SETTING_IMAGE_PROPERTIES]      = KEY_IMAGE_PROPERTIES;
        KEYS_FOR_SETTING[ROW_SETTING_COLOR_EFFECT]          = KEY_COLOR_EFFECT;
        KEYS_FOR_SETTING[ROW_SETTING_SELF_TIMER]            = KEY_SELF_TIMER;
        KEYS_FOR_SETTING[ROW_SETTING_ZSD]                   = KEY_CAMERA_ZSD;
        KEYS_FOR_SETTING[ROW_SETTING_CONTINUOUS]            = KEY_CONTINUOUS_NUMBER;
        KEYS_FOR_SETTING[ROW_SETTING_RECORD_LOCATION]       = KEY_RECORD_LOCATION;//need recheck
        KEYS_FOR_SETTING[ROW_SETTING_PICTURE_SIZE]          = KEY_PICTURE_SIZE;
        KEYS_FOR_SETTING[ROW_SETTING_ISO]                   = KEY_ISO;
        KEYS_FOR_SETTING[ROW_SETTING_ANTI_FLICKER]          = KEY_ANTI_BANDING;
        KEYS_FOR_SETTING[ROW_SETTING_VIDEO_STABLE]          = KEY_VIDEO_EIS;
        KEYS_FOR_SETTING[ROW_SETTING_MICROPHONE]            = KEY_VIDEO_RECORD_AUDIO;
        KEYS_FOR_SETTING[ROW_SETTING_AUDIO_MODE]            = KEY_VIDEO_HD_AUDIO_RECORDING;
        KEYS_FOR_SETTING[ROW_SETTING_TIME_LAPSE]            = KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL;
        KEYS_FOR_SETTING[ROW_SETTING_VIDEO_QUALITY]         = KEY_VIDEO_QUALITY;
        KEYS_FOR_SETTING[ROW_SETTING_PICTURE_RATIO]         = KEY_PICTURE_RATIO;
        KEYS_FOR_SETTING[ROW_SETTING_VOICE]                 = KEY_VOICE;
        KEYS_FOR_SETTING[ROW_SETTING_3DNR]                  = KEY_VIDEO_3DNR;
        KEYS_FOR_SETTING[ROW_SETTING_SLOW_MOTION]           = KEY_SLOW_MOTION;
        KEYS_FOR_SETTING[ROW_SETTING_SLOW_MOTION_VIDEO_QUALITY]     = KEY_SLOW_MOTION_VIDEO_QUALITY;
        KEYS_FOR_SETTING[ROW_SETTING_AIS]                   = KEY_CAMERA_AIS;

         
        KEYS_FOR_SETTING[ROW_SETTING_SHARPNESS]             = KEY_EDGE;
        KEYS_FOR_SETTING[ROW_SETTING_HUE]                   = KEY_HUE;
        KEYS_FOR_SETTING[ROW_SETTING_SATURATION]            = KEY_SATURATION;
        KEYS_FOR_SETTING[ROW_SETTING_BRIGHTNESS]            = KEY_BRIGHTNESS;
        KEYS_FOR_SETTING[ROW_SETTING_CONTRAST]              = KEY_CONTRAST;
        KEYS_FOR_SETTING[ROW_SETTING_CAMERA_MODE]           = KEY_CAMERA_MODE;
        KEYS_FOR_SETTING[ROW_SETTING_CAPTURE_MODE]          = KEY_CAPTURE_MODE;
        KEYS_FOR_SETTING[ROW_SETTING_CONTINUOUS_NUM]        = KEY_CONTINUOUS_NUMBER;
        KEYS_FOR_SETTING[ROW_SETTING_RECORDING_HINT]        = KEY_RECORDING_HIHT;
        KEYS_FOR_SETTING[ROW_SETTING_JPEG_QUALITY]          = KEY_JPEG_QUALITY;
        KEYS_FOR_SETTING[ROW_SETTING_STEREO_MODE]           = KEY_STEREO3D_MODE;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_PROPERTIES] = KEY_FACE_BEAUTY_PROPERTIES;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_SMOOTH]     = KEY_FACE_BEAUTY_SMOOTH;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_SKIN_COLOR] = KEY_FACE_BEAUTY_SKIN_COLOR;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_SHARP]      = KEY_FACE_BEAUTY_SHARP;
        KEYS_FOR_SETTING[ROW_SETTING_CAMERA_FACE_DETECT]    = KEY_CAMERA_FACE_DETECT;
        KEYS_FOR_SETTING[ROW_SETTING_HDR]                   = KEY_HDR;
        KEYS_FOR_SETTING[ROW_SETTING_SMILE_SHOT]            = KEY_SMILE_SHOT;
        KEYS_FOR_SETTING[ROW_SETTING_ASD]                   = KEY_ASD;
        KEYS_FOR_SETTING[ROW_SETTING_MUTE_RECORDING_SOUND]  = KEY_MUTE_RECORDING_SOUND;
        KEYS_FOR_SETTING[ROW_SETTING_GESTURE_SHOT]          = KEY_GESTURE_SHOT;
        KEYS_FOR_SETTING[ROW_SETTING_MULTI_FACE_MODE]       = KEY_MULTI_FACE_BEAUTY;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_SLIM]       = KEY_FACE_BEAUTY_SLIM;
        KEYS_FOR_SETTING[ROW_SETTING_FACEBEAUTY_BIG_EYES]   = KEY_FACE_BEAUTY_BIG_EYES;
        KEYS_FOR_SETTING[ROW_SETTING_DUAL_CAMERA_MODE]      = KEY_DUAL_CAMERA_MODE;
        KEYS_FOR_SETTING[ROW_SETTING_FAST_AF]               = KEY_FAST_AF;
        KEYS_FOR_SETTING[ROW_SETTING_DISTANCE]              = KEY_DISTANCE;
        KEYS_FOR_SETTING[ROW_SETTING_FACE_BEAUTY]           = KEY_FACE_BEAUTY;
        KEYS_FOR_SETTING[ROW_SETTING_PANORAMA]              = KEY_PANORAMA;
        KEYS_FOR_SETTING[ROW_SETTING_MAV]                   = KEY_MAV;
        KEYS_FOR_SETTING[ROW_SETTING_MOTION_TRACK]          = KEY_MOTION_TRACK;
        KEYS_FOR_SETTING[ROW_SETTING_PHOTO_PIP]             = KEY_PHOTO_PIP;
        KEYS_FOR_SETTING[ROW_SETTING_VIDEO_PIP]             = KEY_VIDEO_PIP;
        KEYS_FOR_SETTING[ROW_SETTING_LIVE_PHOTO]            = KEY_LIVE_PHOTO;
        KEYS_FOR_SETTING[ROW_SETTING_VIDEO]                 = KEY_VIDEO;
        KEYS_FOR_SETTING[ROW_SETTING_REFOCUS]               = KEY_REFOCUS;
        KEYS_FOR_SETTING[ROW_SETTING_NORMAL]                = KEY_NORMAL;
        KEYS_FOR_SETTING[ROW_SETTING_OBJECT_TRACKING]       = KEY_OBJECT_TRACKING;
        KEYS_FOR_SETTING[ROW_SETTING_GANGYUN_BEAUTY]           = KEY_GYBEAUTY_MODE;//gangyun tech add 
        KEYS_FOR_SETTING[ROW_SETTING_SELF_PREVIEW]           = KEY_SELF_PREVIEW;//xxw
        KEYS_FOR_SETTING[ROW_SETTING_GRADIENTER]           = KEY_GRADIENTER;//xxw
        KEYS_FOR_SETTING[ROW_SETTING_TAP_TO_CAPTURE]           = KEY_TAP_TO_CAPTURE;//xxw        
        KEYS_FOR_SETTING[ROW_SETTING_VOLUME_KEY]           = KEY_SET_VOLUME_KEY;//dewav link.lin add 
    };
    
    public static final int[] SETTING_GROUP_COMMON_FOR_TAB = new int[]{
        ROW_SETTING_DUAL_CAMERA_MODE,
        ROW_SETTING_RECORD_LOCATION,//common
        ROW_SETTING_MULTI_FACE_MODE,
        ROW_SETTING_EXPOSURE,//common
        ROW_SETTING_COLOR_EFFECT,//common
        ROW_SETTING_SCENCE_MODE,//common
        ROW_SETTING_WHITE_BALANCE,//common
        ROW_SETTING_IMAGE_PROPERTIES,
        ROW_SETTING_ANTI_FLICKER,//common
    };
 全部是设置界面的的item的key字符串,根据这些key值直接找到对应的preference

接着mSettingController.getListPreference(String key)映射到Camera_Preferences.xml

<PreferenceGroup
        xmlns:camera="http://schemas.android.com/apk/res/com.android.gallery3d"
        camera:title="@string/pref_camera_settings_category">
    <IconListPreference
            camera:key="pref_camera_flashmode_key"
            camera:defaultValue="@string/pref_camera_flashmode_default"
            camera:title="@string/pref_camera_flashmode_title"
            camera:icons="@array/camera_flashmode_icons"
            camera:entries="@array/pref_camera_flashmode_entries"
            camera:entryValues="@array/pref_camera_flashmode_entryvalues" />
    <IconListPreference
            camera:key="pref_camera_exposure_key"
            camera:defaultValue="@string/pref_exposure_default"
            camera:title="@string/pref_exposure_title"
            camera:icons="@array/camera_exposure_icons"
            camera:entries="@array/pref_camera_exposure_entries"
            camera:entryValues="@array/pref_camera_exposure_entryvalues" />
    <IconListPreference
            camera:key="pref_camera_scenemode_key"
            camera:defaultValue="@string/pref_camera_scenemode_default"
            camera:title="@string/pref_camera_scenemode_title"
            camera:icons="@array/camera_scenemode_icons"
            camera:entries="@array/pref_camera_scenemode_entries"
            camera:entryValues="@array/pref_camera_scenemode_entryvalues" />
    <IconListPreference
            camera:key="pref_camera_whitebalance_key"
            camera:defaultValue="@string/pref_camera_whitebalance_default"
            camera:title="@string/pref_camera_whitebalance_title"
            camera:icons="@array/whitebalance_icons"
            camera:entries="@array/pref_camera_whitebalance_entries"
            camera:entryValues="@array/pref_camera_whitebalance_entryvalues" />
    <RecordLocationPreference
            camera:key="pref_camera_recordlocation_key"
            camera:defaultValue="@string/pref_camera_recordlocation_default"
            camera:title="@string/pref_camera_record_location_title"
            camera:entries="@array/pref_camera_recordlocation_entries"
            camera:entryValues="@array/pref_camera_recordlocation_entryvalues" />
    <!-- camera:icons="@array/camera_recordlocation_icons" -->
    <ListPreference
            camera:key="pref_camera_picturesize_key"
            camera:title="@string/pref_camera_picturesize_title"
            camera:entries="@array/pref_camera_picturesize_entries"
            camera:entryValues="@array/pref_camera_picturesize_entryvalues" />
    <IconListPreference
            camera:key="pref_camera_id_key"
            camera:defaultValue="@string/pref_camera_id_default"
            camera:title="@string/pref_camera_id_title"
            camera:icons="@array/camera_id_icons"
            camera:entries="@array/camera_id_entries" />
    <!-- ISO -->
    <ListPreference
        camera:key="pref_camera_iso_key"
        camera:defaultValue="@string/pref_camera_iso_default"
        camera:title="@string/pref_camera_iso_title"
        camera:entries="@array/pref_camera_iso_entries"
        camera:entryValues="@array/pref_camera_iso_entryvalues"/>
    <IconListPreference
            camera:key="perf_camera_ais_key"
            camera:defaultValue="@string/pref_camera_ais_default"
            camera:title="@string/pref_camera_ais_title"
            camera:entries="@array/pref_camera_ais_entries"
            camera:entryValues="@array/pref_camera_ais_entryvalues"/>

    <!-- Image adjustment -->
        <!-- Edge -->
        <ListPreference
            camera:key="pref_camera_edge_key"
            camera:defaultValue="@string/pref_camera_edge_default"
            camera:title="@string/pref_camera_edge_title"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_dip_entryvalues" />
        <!-- Hue -->
        <ListPreference
            camera:key="pref_camera_hue_key"
            camera:defaultValue="@string/pref_camera_hue_default"
            camera:title="@string/pref_camera_hue_title"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_dip_entryvalues" />
        <!-- Saturation -->
        <ListPreference
            camera:key="pref_camera_saturation_key"
            camera:defaultValue="@string/pref_camera_saturation_default"
            camera:title="@string/pref_camera_saturation_title"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_dip_entryvalues" />
        <!-- Brightness -->
        <ListPreference
            camera:key="pref_camera_brightness_key"
            camera:defaultValue="@string/pref_camera_brightness_default"
            camera:title="@string/pref_camera_brightness_title"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_dip_entryvalues" />
        <!-- Contrast -->
        <ListPreference
            camera:key="pref_camera_contrast_key"
            camera:defaultValue="@string/pref_camera_contrast_default"
            camera:title="@string/pref_camera_contrast_title"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_dip_entryvalues" />
    <!--  Effects -->
    <IconListPreference
        camera:key="pref_camera_coloreffect_key"
        camera:defaultValue="@string/pref_camera_coloreffect_default"
        camera:title="@string/pref_camera_coloreffect_title"
        camera:icons="@array/camera_coloreffect_icons"
        camera:entries="@array/pref_camera_coloreffect_entries"
        camera:entryValues="@array/pref_camera_coloreffect_entryvalues" />
        
    <!-- Self timer setting -->
    <IconListPreference
        camera:key="pref_camera_self_timer_key"
        camera:defaultValue="@string/pref_camera_selftimer_default"
        camera:title="@string/pref_camera_selftimer_title"
        camera:icons="@array/camera_selftimer_icons"
        camera:entries="@array/pref_camera_selftimer_entries"
        camera:entryValues="@array/pref_camera_selftimer_entryvalues"/>
        
    <!-- anti-flicker -->
    <ListPreference
        camera:key="pref_camera_antibanding_key"
        camera:defaultValue="@array/pref_camera_antibanding_default_array"
        camera:title="@string/pref_camera_antibanding_title"
        camera:entries="@array/pref_camera_antibanding_entries"
        camera:entryValues="@array/pref_camera_antibanding_entryvalues" />

    <ListPreference
        camera:key="pref_camera_zsd_key"
        camera:defaultValue="@string/pref_camera_zsd_default"
        camera:title="@string/pref_camera_zsd_title"
        camera:entries="@array/pref_camera_zsd_entries"
        camera:entryValues="@array/pref_camera_zsd_entryvalues" />

    <ListPreference
        camera:key="pref_camera_shot_number"
        camera:defaultValue="@string/pref_camera_continuous_number_default"
        camera:title="@string/pref_camera_continuous_number_title"
        camera:entries="@array/pref_camera_continuous_number_entries"
        camera:entryValues="@array/pref_camera_continuous_number_entryvalues" />

    <!-- video setting start --> 
    <IconListPreference
            camera:key="pref_video_quality_key"
            camera:defaultValue="@string/pref_video_record_quality_default"
            camera:title="@string/pref_video_quality_title"
            camera:entries="@array/pref_video_quality_entries"
            camera:entryValues="@array/pref_video_quality_entryvalues"/>
    <IconListPreference
            camera:key="pref_slow_motion_video_quality_key"
            camera:defaultValue="@string/pref_slow_motion_video_record_quality_default"
            camera:title="@string/pref_slow_motion_video_quality_title"
            camera:entries="@array/pref_slow_motion_video_quality_entries"
            camera:entryValues="@array/pref_slow_motion_video_quality_entryvalues"/>
    <IconListPreference
            camera:key="pref_video_time_lapse_frame_interval_key"
            camera:defaultValue="@string/pref_video_time_lapse_frame_interval_default"
            camera:title="@string/pref_video_time_lapse_frame_interval_title"
            camera:icons="@array/video_timelapse_icons"
            camera:entries="@array/pref_video_time_lapse_frame_interval_entries"
            camera:entryValues="@array/pref_video_time_lapse_frame_interval_entryvalues"/>
    <ListPreference
            camera:key="pref_camera_recordaudio_key"
            camera:defaultValue="@string/pref_camera_recordaudio_default"
            camera:title="@string/pref_camera_recordaudio_title"
            camera:entries="@array/pref_camera_recordaudio_entries"
            camera:entryValues="@array/pref_camera_recordaudio_entryvalues"/>
      <ListPreference 
            camera:key="pref_camera_video_hd_recording_key"
            camera:defaultValue="@string/pref_video_hd_recording_default" 
            camera:title="@string/pref_camera_video_hd_recording_title" 
            camera:entries="@array/pref_camera_video_hd_recording_entries" 
            camera:entryValues="@array/pref_camera_video_hd_recording_entryvalues" />
       <!-- video setting end -->
       <ListPreference 
            camera:key="pref_camera_image_properties_key"
            camera:defaultValue="@string/pref_camera_image_properties_default" 
            camera:title="@string/pref_camera_image_properties_title"
            camera:entries="@array/pref_camera_image_properties_entries"
            camera:entryValues="@array/pref_camera_image_properties_entryvalues" />
    <ListPreference
        camera:defaultValue="@string/pref_dual_camera_default"
        camera:entries="@array/pref_dual_camera_entries"
        camera:entryValues="@array/pref_dual_camera_entryvalues"
        camera:key="pref_dual_camera_key"
        camera:title="@string/pref_dual_camera_switch" />
    <ListPreference
        camera:defaultValue="@string/pref_fast_af_default"
        camera:entries="@array/pref_dual_camera_dip_entries"
        camera:entryValues="@array/pref_dual_camera_dip_entryvalues"
        camera:key="pref_fast_af_key"
        camera:title="@string/pref_fast_af_title" />
    <ListPreference
        camera:defaultValue="@string/pref_distance_default"
        camera:entries="@array/pref_dual_camera_dip_entries"
        camera:entryValues="@array/pref_dual_camera_dip_entryvalues"
        camera:key="pref_distance_key"
        camera:title="@string/pref_distance_info_title" />
    <ListPreference
            camera:key="pref_camera_picturesize_ratio_key"
            camera:title="@string/pref_camera_picturesize_ratio_title"
            camera:entries="@array/pref_camera_picturesize_ratio_entries"
            camera:entryValues="@array/pref_camera_picturesize_ratio_entryvalues" />
    <IconListPreference 
            camera:key="pref_voice_key"
            camera:defaultValue="@string/pref_voice_default" 
            camera:title="@string/pref_voice_capture"
            camera:icons="@array/voice_icons"
            camera:entries="@array/pref_voice_entries"
            camera:entryValues="@array/pref_voice_entryvalues" />
    <IconListPreference
            camera:key="pref_slow_motion_key"
            camera:defaultValue="@string/pref_slow_motion_default" 
            camera:title="@string/pref_slow_motion"
            camera:icons="@array/slow_motion_icons"
            camera:entries="@array/pref_slow_motion_entries"
            camera:entryValues="@array/pref_slow_motion_entryvalues" />
    <ListPreference 
            camera:key="pref_video_hdr_key"
            camera:defaultValue="@string/pref_video_hdr_default" 
            camera:title="@string/pref_video_hdr_title"
            camera:entries="@array/pref_video_hdr_entries"
            camera:entryValues="@array/pref_video_hdr_entryvalues" />
        <ListPreference 
            camera:key="pref_camera_facebeauty_properties_key"
            camera:defaultValue="@string/pref_camera_facebeauty_properties_default" 
            camera:title="@string/pref_camera_facebeauty_properties_title"
            camera:entries="@array/pref_camera_facebeauty_properties_entries"
            camera:entryValues="@array/pref_camera_facebeauty_properties_entryvalues" />
    <!-- facebeauty adjustment -->
        <!-- Smooth -->
        <IconListPreference
            camera:key="pref_facebeauty_smooth_key"
            camera:defaultValue="@string/pref_facebeauty_smooth_default"
            camera:title="@string/pref_facebeauty_smooth_title"
            camera:icons="@array/facebeauty_smooth_icons"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_facebeauty_turning_entryvalues" />
        <!-- Skin color -->
        <IconListPreference
            camera:key="pref_facebeauty_skin_color_key"
            camera:defaultValue="@string/pref_facebeauty_skin_color_default"
            camera:title="@string/pref_facebeauty_skin_color_title"
            camera:icons="@array/facebeauty_skin_color_icons"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_facebeauty_turning_entryvalues" />
        <!-- Sharp -->
        <IconListPreference
            camera:key="pref_facebeauty_sharp_key"
            camera:defaultValue="@string/pref_facebeauty_sharp_default"
            camera:title="@string/pref_facebeauty_sharp_title"
            camera:icons="@array/facebeauty_sharp_icons"
            camera:entries="@array/pref_camera_dip_entries"
            camera:entryValues="@array/pref_camera_facebeauty_turning_entryvalues" />
        <ListPreference
            camera:key="pref_video_eis_key"
            camera:defaultValue="@string/pref_camera_eis_default"
            camera:title="@string/pref_camera_eis_title"
            camera:entries="@array/pref_camera_eis_entries"
            camera:entryValues="@array/pref_camera_eis_entryvalues"/>
        <ListPreference
            camera:key="pref_video_3dnr_key"
            camera:defaultValue="@string/pref_camera_3dnr_default"
            camera:title="@string/pref_camera_3dnr_title"
            camera:entries="@array/pref_camera_3dnr_entries"
            camera:entryValues="@array/pref_camera_3dnr_entryvalues"/>
        <ListPreference
            camera:key="pref_face_detect_key"
            camera:defaultValue="@string/pref_camera_face_detect_default"
            camera:title="@string/pref_camera_face_detect_title"
            camera:entries="@array/pref_camera_face_detect_entries"
            camera:entryValues="@array/pref_camera_face_detect_entryvalues"/>
            
        <ListPreference
            camera:key="pref_face_beauty_multi_mode_key"
            camera:title="@string/pref_face_beauty_mode_title"
            camera:entries="@array/pref_camera_multi_face_beauty_entries"
            camera:entryValues="@array/pref_camera_multi_face_beauty_entryvalues"/>
        <!-- Added by Joseth @{ -->
        <ListPreference
            camera:key="pref_self_preview_key"
            camera:defaultValue="@string/pref_camera_self_preview_default"
            camera:title="@string/pref_camera_self_preview_title"
            camera:entries="@array/pref_camera_self_preview_entries"
            camera:entryValues="@array/pref_camera_self_preview_entryvalues"/>
		<!-- @} -->
    	<!-- Gordon: Gradienter @{ -->
    	<ListPreference
        	camera:key="pref_gradienter_key"
        	camera:defaultValue="@string/pref_camera_gradienter_default"
        	camera:title="@string/pref_camera_gradienter_title"
        	camera:entries="@array/pref_camera_gradienter_entries"
        	camera:entryValues="@array/pref_camera_gradienter_entryvalues"/>
    	<!-- Gordon: @} -->
		<ListPreference
		    camera:key="pref_tap_to_capture_key"
		    camera:defaultValue="@string/pref_camera_tap_to_capture_default"
		    camera:title="@string/pref_camera_tap_to_capture_title"
		    camera:entries="@array/pref_camera_tap_to_capture_entries"
		    camera:entryValues="@array/pref_camera_tap_to_capture_entryvalues"/>
            
        <!-- mcoy add begin for volume keys -->
        <ListPreference
            camera:key="pref_set_volume_key"
            camera:defaultValue="0"
            camera:title="@string/pref_set_volume_key_title"
            camera:entries="@array/pref_set_volume_key_entries"
            camera:entryValues="@array/pref_set_volume_key_entryvalues"/>
        <!-- mcoy add end for volume keys-->

    <IconListPreference
            camera:key="pref_hdr_key"
            camera:defaultValue="@string/pref_camera_hdr_default"
            camera:title="@string/pref_camera_hdr_title"
            camera:icons="@array/pref_hdr_icons"
            camera:entries="@array/pref_camera_hdr_entries"
            camera:entryValues="@array/pref_camera_hdr_entryvalues"/>
    <IconListPreference
            camera:key="pref_smile_shot_key"
            camera:defaultValue="@string/pref_smile_shot_default"
            camera:title="@string/pref_smile_shot_title"
            camera:icons="@array/pref_smile_shot_icons"
            camera:entries="@array/pref_smile_shot_entries"
            camera:entryValues="@array/pref_smile_shot_entryvalues"/>
    <ListPreference
            camera:key="pref_asd_key"
            camera:defaultValue="@string/pref_asd_default"
            camera:title="@string/pref_asd_title"
            camera:entries="@array/pref_asd_entries"
            camera:entryValues="@array/pref_asd_entryvalues"/>
    <IconListPreference
            camera:key="pref_gesture_shot_key"
            camera:defaultValue="@string/pref_gesture_shot_default"
            camera:title="@string/pref_camera_capturemode_entry_gestureshot"
            camera:icons="@array/pref_gesture_shot_icons"
            camera:entries="@array/pref_gesture_shot_entries"
            camera:entryValues="@array/pref_gesture_shot_entryvalues"/>
  <!--add by gangyun tech-->
    <IconListPreference
            camera:key="pref_camera_gybeauty_key"
            camera:defaultValue="@string/pref_gybeauty_entry_on"
            camera:icons="@array/gybeauty_icons"
            camera:title="@string/gy_faceart_guide_capture"
            camera:entries="@array/pref_camera_gybeauty_entries"
            camera:entryValues="@array/pref_camera_gybeauty_entryvalues" />
 <!--end by gangyun tech--> 
</PreferenceGroup>

  这时候pageView.initialize(getListPreferences(holder.mSettingKeys, i == 0));中的getListPreferences方法结束,此时返回了ArrayList<listPreference>作为initialize方法的参数传入,看下initialize方法。其中用一个SettingsListAdapter的适配器对解析的listview进行初始化

public void initialize(ArrayList<ListPreference> listItems) {
        mListItem = listItems;
        
        mListItemAdapter = new SettingsListAdapter();
        mSettingList.setAdapter(mListItemAdapter);
        mSettingList.setOnItemClickListener(this);
        mSettingList.setSelector(android.R.color.transparent);
        mSettingList.setOnScrollListener(this);
    }

目前先看到这

发现yaw的值在一定时间后会被锁死(oled屏幕上数字不发生改变),查找原因,查找原因修正 empty.c #include <math.h> // 添加数学库用于fabs函数 #include "board.h" #include "my_key.h" #include "my_time.h" #include "ti_msp_dl_config.h" #include "oled.h" void BUZZY_OFF(void) { DL_GPIO_setPins(BUZZY_PORT, BUZZY_PIN_PIN); } void BUZZY_ON(void) { DL_GPIO_clearPins(BUZZY_PORT, BUZZY_PIN_PIN); } void refresh_oled(void); void key(void); void go_straight(int dis); void go_arc_ccd(hsu_time_t); void go_brc_ccd(hsu_time_t); void turn_in_place(float angle); void sound_light_alert(void); void show_task_now(void); u8 Car_Mode = Diff_Car; int Motor_Left, Motor_Right; // 电机PWM变量 应是Motor的 u8 PID_Send; // 延时和调参相关变量 float RC_Velocity = 200, RC_Turn_Velocity, Move_X, Move_Y, Move_Z, PS2_ON_Flag; // 遥控控制的速度 float Velocity_Left, Velocity_Right; // 车轮速度(mm/s) u16 test_num, show_cnt; float Voltage = 0; extern float Yaw; // 声明外部YAW角度变量 int64_t left_encoder = 0, right_encoder = 0; void SysTick_Handler(void) { hsu_time_systick_handler(); } typedef enum { BEGIN, T1, T2, T3, T4 } TaskState; typedef enum { STOP, GO_STRAIGHT, GO_CCD, TURN_IN_PLACE, WAIT_ALERT } DoingWhat; typedef struct __TASK_NAMESPACE { uint8_t is; uint8_t is_running; uint8_t finish; uint8_t sub_finish; uint8_t running_state; // 0: 停止, 1: 运行中 TaskState state; DoingWhat doing_what; float target; float vx; float vz; // 用于复杂任务 uint8_t sub_task_stage; // 子任务阶段 uint8_t lap_count; // 圈数计数 int64_t start_encoder; // 起始编码器值 uint32_t alert_start_time; // 声光提示开始时间 float start_yaw; // 起始YAW角度 float target_yaw_diff; // 目标YAW角度差 hsu_time_t ccd_end_time; } TaskNamespace; void reset_task_namespace(TaskNamespace *t) { t->is_running = 0; t->finish = 0; t->sub_finish = 0; t->state = BEGIN; t->doing_what = STOP; t->vx = 0; t->vz = 0; t->sub_task_stage = 0; t->lap_count = 0; t->start_encoder = left_encoder; t->alert_start_time = 0; t->start_yaw = 0; t->target_yaw_diff = 0; t->running_state = 0; // 明确重置运行状态为0 t->ccd_end_time = 0; t->is = 0; } void next_state(TaskNamespace *t) { TaskState last_state = t->state; reset_task_namespace(t); if (last_state < T4) { t->state = last_state + 1; } } TaskNamespace task_namespace; void show_task_now(void) { //OLED_ShowString(0, 0, "Task Now:"); switch (task_namespace.state) { case BEGIN: OLED_ShowString(1, 10,"0"); break; case T1: OLED_ShowString(1, 10,"1"); break; case T2: OLED_ShowString(1, 10,"2"); break; case T3: OLED_ShowString(1, 10,"3"); break; case T4: OLED_ShowString(1, 10,"4"); break; default: break; } } void main_task(void); int main(void) { // 系统初始化 SYSCFG_DL_init(); // 初始化系统配置 hsu_time_init(); // 时间 // 清除所有外设的中断挂起状态 NVIC_ClearPendingIRQ(ENCODERA_INT_IRQN); // 编码器A中断 NVIC_ClearPendingIRQ(ENCODERB_INT_IRQN); // 编码器B中断 NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); // UART0串口中断 // 使能各外设的中断 NVIC_EnableIRQ(ENCODERA_INT_IRQN); // 开启编码器A中断 NVIC_EnableIRQ(ENCODERB_INT_IRQN); // 开启编码器B中断 NVIC_EnableIRQ(UART_0_INST_INT_IRQN); // 开启UART0中断 reset_task_namespace(&task_namespace); task_namespace.state = BEGIN; // 明确设置初始状态 // 定时器和ADC相关中断配置 NVIC_ClearPendingIRQ(TIMER_0_INST_INT_IRQN); // 清除定时器0中断挂起 NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN); // 开启定时器0中断 NVIC_EnableIRQ(ADC12_VOLTAGE_INST_INT_IRQN); NVIC_EnableIRQ(ADC12_CCD_INST_INT_IRQN); OLED_Init(); // 初始化OLED显示屏 OLED_ShowString(1, 1, "Task Now:"); OLED_ShowString(2, 1, "state:"); OLED_ShowString(3, 1, "yaw:"); MPU6050_initialize(); DMP_Init(); BUZZY_ON(); // 主循环 // printf("Test delay 500us\n"); // hsu_time_delay_us(500); // printf("Test delay 500us end\n"); uint8_t main_task_timer = hsu_time_timer_create(10, true, main_task); hsu_time_timer_start(main_task_timer); uint8_t refresh_oled_timer = hsu_time_timer_create(5, true, refresh_oled); hsu_time_timer_start(refresh_oled_timer); uint8_t key_timer = hsu_time_timer_create(2, true, key); hsu_time_timer_start(key_timer); while (1) { hsu_time_timer_process(); RD_TSL(); // 读取CCD数据 Find_CCD_Median(); // 计算CCD数据中值 Read_DMP(); show_task_now(); char yaw_str[10]; // 存储格式化后的字符串 snprintf(yaw_str, sizeof(yaw_str), "%.1f", Yaw); // 格式化为带一位小数的字符串 OLED_ShowString(3, 6, yaw_str); // 在指定位置显示YAW值 //DL_GPIO_togglePins(LED_PORT, LED_led_PIN); // printf("L=%lld R=%lld YAW=%.1f\n", left_encoder, right_encoder, Yaw); } } void task_no(void); void task_1(void); void task_2(void); void task_3(void); void task_4(void); void main_task(void) { if (!(task_namespace.is)) return; printf("main task\n"); switch (task_namespace.state) { case BEGIN: task_no(); break; case T1: task_1(); break; case T2: task_2(); break; case T3: task_3(); break; case T4: task_4(); break; default: break; } switch (task_namespace.doing_what) { case STOP: Get_Target_Encoder(0, 0); break; case GO_STRAIGHT: if ((left_encoder * 1.f) < task_namespace.target) { Get_Target_Encoder(0.3, 0); // 提高速度到300mm/s } else { Get_Target_Encoder(0, 0); task_namespace.doing_what = STOP; task_namespace.finish = 1; } break; case GO_CCD: if (task_namespace.ccd_end_time < hsu_time_get_ms()) { Get_Target_Encoder(0, 0); task_namespace.doing_what = STOP; task_namespace.finish = 1; } else { CCD_Mode(); } break; case TURN_IN_PLACE: // 原地转向控制 if (task_namespace.target_yaw_diff != 0) { float current_yaw_diff = Yaw - task_namespace.start_yaw; // 处理角度跨越±180度的情况 if (current_yaw_diff > 180) { current_yaw_diff -= 360; } else if (current_yaw_diff < -180) { current_yaw_diff += 360; } printf("Turn: Start=%.1f Current=%.1f Diff=%.1f Target=%.1f\n", task_namespace.start_yaw, Yaw, current_yaw_diff, task_namespace.target_yaw_diff); // 检查是否达到目标角度 if ((task_namespace.target_yaw_diff > 0 && current_yaw_diff >= task_namespace.target_yaw_diff) || (task_namespace.target_yaw_diff < 0 && current_yaw_diff <= task_namespace.target_yaw_diff)) { Get_Target_Encoder(0, 0); // 停止转向 task_namespace.doing_what = STOP; task_namespace.finish = 1; } else { // 继续转向 float turn_speed = (task_namespace.target_yaw_diff > 0) ? 0.1 : -0.1; Get_Target_Encoder(0, turn_speed); } } break; case WAIT_ALERT: Get_Target_Encoder(0, 0); // 停车 if (hsu_time_get_ms() - task_namespace.alert_start_time > 1000) { // 声光提示1秒 task_namespace.doing_what = STOP; task_namespace.finish = 1; } break; default: break; } } void task_no(void) { return; } // 任务1:A点到B点直线行驶 void task_1(void) { if (!task_namespace.is_running) { task_namespace.is_running = 1; task_namespace.sub_task_stage = 0; task_namespace.finish = 1; return; } if (task_namespace.finish) { switch (task_namespace.sub_task_stage) { case 0: // 开始第一阶段:A到B go_straight(300); break; case 1: // A到B完成,开始B到C DL_GPIO_togglePins(LED_PORT, LED_led_PIN); break; case 2: //任务结束 reset_task_namespace(&task_namespace); task_namespace.running_state = 0; // 重置为停止状态 break; } task_namespace.finish = 0; task_namespace.sub_task_stage++; } return; } // 任务2:A->B->C->D->A循环 void task_2(void) { if (!task_namespace.is_running) { task_namespace.is_running = 1; task_namespace.sub_task_stage = 0; task_namespace.finish = 1; return; } if (task_namespace.finish) { switch (task_namespace.sub_task_stage) { case 0: // 开始第一阶段:A到B go_straight(3300); break; case 1: //DL_GPIO_togglePins(LED_PORT, LED_led_PIN); go_straight(2000); break; case 2: // B到C弧线完成,开始C到D直线 sound_light_alert(); //turn_in_place(-17.0f); go_straight(2980); break; case 3: // C到D完成,开始D到A弧线 sound_light_alert(); go_arc_ccd(3530); break; case 4: // D到A弧线完成,任务结束 sound_light_alert(); reset_task_namespace(&task_namespace); break; } task_namespace.finish = 0; task_namespace.sub_task_stage++; } return; } // 任务3:A->C->B->D->A循环 void task_3(void) { if (!task_namespace.is_running) { task_namespace.is_running = 1; task_namespace.sub_task_stage = 0; task_namespace.finish = 1; return; } if (task_namespace.finish) { switch (task_namespace.sub_task_stage) { case 0: turn_in_place(-31.0f); break; case 1: go_straight(4060); break; case 2: turn_in_place(30.0f); break; case 3: // 开始C到B弧线 sound_light_alert(); //go_straight(40); go_brc_ccd(3550); break; case 4: turn_in_place(36.0f); break; case 5: sound_light_alert(); go_straight(3985); break; case 6: turn_in_place(-40.0f); break; case 7: // 开始C到B弧线 sound_light_alert(); go_arc_ccd(3600); break; case 8: // D到A弧线完成,任务结束 sound_light_alert(); reset_task_namespace(&task_namespace); break; } task_namespace.finish = 0; task_namespace.sub_task_stage++; } return; } // 任务4:重复任务3路径4圈 void task_4(void) { if (!task_namespace.is_running) { task_namespace.is_running = 1; task_namespace.sub_task_stage = 0; task_namespace.finish = 1; return; } if (task_namespace.finish) { switch (task_namespace.sub_task_stage) { case 0: turn_in_place(-30.0f); break; case 1: go_straight(4045); break; case 2: turn_in_place(29.0f); break; case 3: // 开始C到B弧线 sound_light_alert(); //go_straight(40); go_brc_ccd(5000); break; case 4: turn_in_place(34.0f); break; case 5: sound_light_alert(); go_straight(4035); break; case 6: turn_in_place(-33.0f); break; case 7: // 开始C到B弧线 sound_light_alert(); go_arc_ccd(5000); break; case 8: // D到A弧线完成,任务结束 sound_light_alert(); reset_task_namespace(&task_namespace); break; } task_namespace.finish = 0; task_namespace.sub_task_stage++; } } void TIMER_0_INST_IRQHandler(void) { if (DL_TimerA_getPendingInterrupt(TIMER_0_INST)) { if (DL_TIMER_IIDX_ZERO) { Get_Velocity_From_Encoder(Get_Encoder_countA, Get_Encoder_countB); Get_Encoder_countA = Get_Encoder_countB = 0; MotorA.Motor_Pwm = Incremental_PI_Left(MotorA.Current_Encoder, MotorA.Target_Encoder); MotorB.Motor_Pwm = Incremental_PI_Right(MotorB.Current_Encoder, MotorB.Target_Encoder); if (!Flag_Stop) { Set_PWM(-MotorA.Motor_Pwm, -MotorB.Motor_Pwm); } else { Set_PWM(0, 0); } } } } uint32_t gpio_interrup1, gpio_interrup2; int64_t B1, B2, B3, B4; int64_t A1, A2, A3, A4; void GROUP1_IRQHandler(void) { // 获取中断信号 gpio_interrup1 = DL_GPIO_getEnabledInterruptStatus(ENCODERA_PORT, ENCODERA_E1A_PIN | ENCODERA_E1B_PIN); gpio_interrup2 = DL_GPIO_getEnabledInterruptStatus(ENCODERB_PORT, ENCODERB_E2A_PIN | ENCODERB_E2B_PIN); // encoderB if ((gpio_interrup1 & ENCODERA_E1A_PIN) == ENCODERA_E1A_PIN) { if (!DL_GPIO_readPins(ENCODERA_PORT, ENCODERA_E1B_PIN)) { right_encoder--; Get_Encoder_countB--; } else { right_encoder++; Get_Encoder_countB++; } } else if ((gpio_interrup1 & ENCODERA_E1B_PIN) == ENCODERA_E1B_PIN) { if (!DL_GPIO_readPins(ENCODERA_PORT, ENCODERA_E1A_PIN)) { right_encoder++; Get_Encoder_countB++; } else { right_encoder--; Get_Encoder_countB--; } } // encoderA if ((gpio_interrup2 & ENCODERB_E2A_PIN) == ENCODERB_E2A_PIN) { if (!DL_GPIO_readPins(ENCODERB_PORT, ENCODERB_E2B_PIN)) { left_encoder++; Get_Encoder_countA--; } else { left_encoder--; Get_Encoder_countA++; } } else if ((gpio_interrup2 & ENCODERB_E2B_PIN) == ENCODERB_E2B_PIN) { if (!DL_GPIO_readPins(ENCODERB_PORT, ENCODERB_E2A_PIN)) { left_encoder--; Get_Encoder_countA++; } else { left_encoder++; Get_Encoder_countA--; } } DL_GPIO_clearInterruptStatus(ENCODERA_PORT, ENCODERA_E1A_PIN | ENCODERA_E1B_PIN); DL_GPIO_clearInterruptStatus(ENCODERB_PORT, ENCODERB_E2A_PIN | ENCODERB_E2B_PIN); } // 直线行驶函数 void go_straight(int dis) { task_namespace.doing_what = GO_STRAIGHT; task_namespace.target = left_encoder + dis; task_namespace.finish = 0; } // 原地转向函数 void turn_in_place(float angle) { task_namespace.doing_what = TURN_IN_PLACE; task_namespace.start_yaw = Yaw; task_namespace.target_yaw_diff = angle; // 正值右转,负值左转 task_namespace.finish = 0; } // CCD巡线函数(需要外部条件结束) void go_ccd_line(void) { task_namespace.doing_what = GO_CCD; task_namespace.start_encoder = left_encoder; task_namespace.finish = 0; // 设置一个安全的最大距离,防止无限巡线 // 可以根据实际场地调整这个值 static uint32_t ccd_end_time = 0; if (ccd_end_time == 0) { ccd_end_time = hsu_time_get_ms(); } // 如果巡线时间超过10秒或距离超过2000mm,强制结束 if (hsu_time_get_ms() - ccd_end_time > 10000 || (left_encoder * 1.f - task_namespace.start_encoder) > 2000) { task_namespace.finish = 1; ccd_end_time = 0; } } // 弧线CCD巡线函数 void go_arc_ccd(hsu_time_t time) { task_namespace.doing_what = GO_CCD; task_namespace.start_encoder = left_encoder; task_namespace.ccd_end_time = hsu_time_get_ms() + time; } void go_brc_ccd(hsu_time_t time) { task_namespace.doing_what = GO_CCD; task_namespace.start_encoder = right_encoder; task_namespace.ccd_end_time = hsu_time_get_ms() + time; } // 声光提示函数 void sound_light_alert(void) { DL_GPIO_togglePins(LED_PORT, LED_led_PIN); DL_GPIO_setPins(BUZZY_PORT, BUZZY_PIN_PIN); uint32_t start_time = hsu_time_get_ms(); while (hsu_time_get_ms() - start_time < 1000) { // 空循环等待1秒 } //hsu_time_delay_ms(200); DL_GPIO_togglePins(LED_PORT, LED_led_PIN); DL_GPIO_clearPins(BUZZY_PORT, BUZZY_PIN_PIN); } // callback void refresh_oled(void) { show_task_now(); OLED_ShowString(2, 1, "state:"); if (task_namespace.running_state) { OLED_ShowString(2, 7, "1"); // 运行中 } else { OLED_ShowString(2, 7, "0"); // 停止 } } uint32_t key_get_tick_ms(void) { return hsu_time_get_ms(); } void key(void) { key_event_t event = key_scan(); //uint8_t key_value = key_read_pin(); // 获取按键状态 //S1 switch (event) { case KEY_EVENT_SINGLE_CLICK: next_state(&task_namespace); break; case KEY_EVENT_DOUBLE_CLICK: task_namespace.is = 1; task_namespace.running_state = 1; task_namespace.is_running = 0; // 重置任务运行标志 break; } } MPU6050.c #include "MPU6050.h" #include <stdio.h> #include "inv_mpu.h" // #include "IOI2C.h" // #include "usart.h" #define PRINT_ACCEL (0x01) #define PRINT_GYRO (0x02) #define PRINT_QUAT (0x04) #define ACCEL_ON (0x01) #define GYRO_ON (0x02) #define MOTION (0) #define NO_MOTION (1) #define DEFAULT_MPU_HZ (200) #define FLASH_SIZE (512) #define FLASH_MEM_START ((void *)0x1800) #define q30 1073741824.0f short gyro[3], accel[3], sensors; float Roll, Pitch, Yaw; float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; static signed char gyro_orientation[9] = {-1, 0, 0, 0, -1, 0, 0, 0, 1}; Imu_t mpu6050 = {0}; Imu_t RegOri_mpu6050 = {0}; // iic转接 #include "bsp_siic.h" static pIICInterface_t siic = &User_sIICDev; uint8_t IICwriteBits(uint8_t addr, uint8_t reg, uint8_t bitStart, uint8_t length, uint8_t data) { uint8_t b; if (siic->read_reg(addr << 1, reg, &b, 1, 200) == IIC_OK) { uint8_t mask = (0xFF << (bitStart + 1)) | (0xFF >> ((8 - bitStart) + length - 1)); data <<= (8 - length); data >>= (7 - bitStart); b &= mask; b |= data; return siic->write_reg(addr << 1, reg, &b, 1, 200); } return 1; } uint8_t IICwriteBit(uint8_t dev, uint8_t reg, uint8_t bitNum, uint8_t data) { uint8_t b; siic->read_reg(dev << 1, reg, &b, 1, 200); b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); return siic->write_reg(dev << 1, reg, &b, 1, 200); } uint8_t IICreadBytes(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data) { return siic->read_reg(dev << 1, reg, data, length, 200); } int i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf) { return siic->read_reg(addr << 1, reg, buf, len, 200); } unsigned char I2C_ReadOneByte(unsigned char I2C_Addr, unsigned char addr) { uint8_t b = 0; siic->read_reg(I2C_Addr << 1, addr, &b, 1, 200); return b; } static unsigned short inv_row_2_scale(const signed char *row) { unsigned short b; if (row[0] > 0) b = 0; else if (row[0] < 0) b = 4; else if (row[1] > 0) b = 1; else if (row[1] < 0) b = 5; else if (row[2] > 0) b = 2; else if (row[2] < 0) b = 6; else b = 7; // error return b; } static unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx) { unsigned short scalar; scalar = inv_row_2_scale(mtx); scalar |= inv_row_2_scale(mtx + 3) << 3; scalar |= inv_row_2_scale(mtx + 6) << 6; return scalar; } static void run_self_test(void) { int result; long gyro[3], accel[3]; result = mpu_run_self_test(gyro, accel); if (result == 0x7) { /* Test passed. We can trust the gyro data here, so let's push it down * to the DMP. */ float sens; unsigned short accel_sens; mpu_get_gyro_sens(&sens); gyro[0] = (long)(gyro[0] * sens); gyro[1] = (long)(gyro[1] * sens); gyro[2] = (long)(gyro[2] * sens); dmp_set_gyro_bias(gyro); mpu_get_accel_sens(&accel_sens); accel[0] *= accel_sens; accel[1] *= accel_sens; accel[2] *= accel_sens; dmp_set_accel_bias(accel); // printf("setting bias succesfully ......\r\n"); } } uint8_t buffer[14]; int16_t MPU6050_FIFO[6][11]; int16_t Gx_offset = 0, Gy_offset = 0, Gz_offset = 0; /************************************************************************** Function: The new ADC data is updated to FIFO array for filtering Input : ax,ay,az:x,y, z-axis acceleration data;gx,gy,gz:x. Y, z-axis angular acceleration data Output : none 函数功能:将新的ADC数据更新到 FIFO数组,进行滤波处理 入口参数:ax,ay,az:x,y,z轴加速度数据;gx,gy,gz:x,y,z轴角加速度数据 返回 值:无 **************************************************************************/ void MPU6050_newValues(int16_t ax, int16_t ay, int16_t az, int16_t gx, int16_t gy, int16_t gz) { unsigned char i; int32_t sum = 0; for (i = 1; i < 10; i++) { // FIFO 操作 MPU6050_FIFO[0][i - 1] = MPU6050_FIFO[0][i]; MPU6050_FIFO[1][i - 1] = MPU6050_FIFO[1][i]; MPU6050_FIFO[2][i - 1] = MPU6050_FIFO[2][i]; MPU6050_FIFO[3][i - 1] = MPU6050_FIFO[3][i]; MPU6050_FIFO[4][i - 1] = MPU6050_FIFO[4][i]; MPU6050_FIFO[5][i - 1] = MPU6050_FIFO[5][i]; } MPU6050_FIFO[0][9] = ax; // 将新的数据放置到 数据的最后面 MPU6050_FIFO[1][9] = ay; MPU6050_FIFO[2][9] = az; MPU6050_FIFO[3][9] = gx; MPU6050_FIFO[4][9] = gy; MPU6050_FIFO[5][9] = gz; sum = 0; for (i = 0; i < 10; i++) { // 求当前数组的合,再取平均值 sum += MPU6050_FIFO[0][i]; } MPU6050_FIFO[0][10] = sum / 10; sum = 0; for (i = 0; i < 10; i++) { sum += MPU6050_FIFO[1][i]; } MPU6050_FIFO[1][10] = sum / 10; sum = 0; for (i = 0; i < 10; i++) { sum += MPU6050_FIFO[2][i]; } MPU6050_FIFO[2][10] = sum / 10; sum = 0; for (i = 0; i < 10; i++) { sum += MPU6050_FIFO[3][i]; } MPU6050_FIFO[3][10] = sum / 10; sum = 0; for (i = 0; i < 10; i++) { sum += MPU6050_FIFO[4][i]; } MPU6050_FIFO[4][10] = sum / 10; sum = 0; for (i = 0; i < 10; i++) { sum += MPU6050_FIFO[5][i]; } MPU6050_FIFO[5][10] = sum / 10; } /************************************************************************** Function: Setting the clock source of mpu6050 Input : source:Clock source number Output : none 函数功能:设置 MPU6050 的时钟源 入口参数:source:时钟源编号 返回 值:无 * CLK_SEL | Clock Source * --------+-------------------------------------- * 0 | Internal oscillator * 1 | PLL with X Gyro reference * 2 | PLL with Y Gyro reference * 3 | PLL with Z Gyro reference * 4 | PLL with external 32.768kHz reference * 5 | PLL with external 19.2MHz reference * 6 | Reserved * 7 | Stops the clock and keeps the timing generator in reset **************************************************************************/ void MPU6050_setClockSource(uint8_t source) { IICwriteBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, source); } /** Set full-scale gyroscope range. * @param range New full-scale gyroscope range value * @see getFullScaleRange() * @see MPU6050_GYRO_FS_250 * @see MPU6050_RA_GYRO_CONFIG * @see MPU6050_GCONFIG_FS_SEL_BIT * @see MPU6050_GCONFIG_FS_SEL_LENGTH */ void MPU6050_setFullScaleGyroRange(uint8_t range) { IICwriteBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, range); } /************************************************************************** Function: Setting the maximum range of mpu6050 accelerometer Input : range:Acceleration maximum range number Output : none 函数功能:设置 MPU6050 加速度计的最大量程 入口参数:range:加速度最大量程编号 返回 值:无 **************************************************************************/ // #define MPU6050_ACCEL_FS_2 0x00 //===最大量程+-2G // #define MPU6050_ACCEL_FS_4 0x01 //===最大量程+-4G // #define MPU6050_ACCEL_FS_8 0x02 //===最大量程+-8G // #define MPU6050_ACCEL_FS_16 0x03 //===最大量程+-16G void MPU6050_setFullScaleAccelRange(uint8_t range) { IICwriteBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, range); } /************************************************************************** Function: Set mpu6050 to sleep mode or not Input : enable:1,sleep;0,work; Output : none 函数功能:设置 MPU6050 是否进入睡眠模式 入口参数:enable:1,睡觉;0,工作; 返回 值:无 **************************************************************************/ void MPU6050_setSleepEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, enabled); } /************************************************************************** Function: Read identity Input : none Output : 0x68 函数功能:读取 MPU6050 WHO_AM_I 标识 入口参数:无 返回 值:0x68 **************************************************************************/ uint8_t MPU6050_getDeviceID(void) { IICreadBytes(devAddr, MPU6050_RA_WHO_AM_I, 1, buffer); return buffer[0]; } /************************************************************************** Function: Check whether mpu6050 is connected Input : none Output : 1:Connected;0:Not connected 函数功能:检测MPU6050 是否已经连接 入口参数:无 返回 值:1:已连接;0:未连接 **************************************************************************/ uint8_t MPU6050_testConnection(void) { if (MPU6050_getDeviceID() == 0x68) // 0b01101000; return 1; else return 0; } /************************************************************************** Function: Setting whether mpu6050 is the host of aux I2C cable Input : enable:1,yes;0;not Output : none 函数功能:设置 MPU6050 是否为AUX I2C线的主机 入口参数:enable:1,是;0:否 返回 值:无 **************************************************************************/ void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_I2C_MST_EN_BIT, enabled); } /************************************************************************** Function: Setting whether mpu6050 is the host of aux I2C cable Input : enable:1,yes;0;not Output : none 函数功能:设置 MPU6050 是否为AUX I2C线的主机 入口参数:enable:1,是;0:否 返回 值:无 **************************************************************************/ void MPU6050_setI2CBypassEnabled(uint8_t enabled) { IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_I2C_BYPASS_EN_BIT, enabled); } /************************************************************************** Function: initialization Mpu6050 to enter the available state Input : none Output : none 函数功能:初始化 MPU6050 以进入可用状态 入口参数:无 返回 值:无 **************************************************************************/ void MPU6050_initialize(void) { // 未识别陀螺仪,复位 if (MPU6050_getDeviceID() != 0x68) DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_POR); MPU6050_setClockSource(MPU6050_CLOCK_PLL_YGYRO); // 设置时钟 MPU6050_setFullScaleGyroRange(MPU6050_GYRO_FS_2000); // 陀螺仪量程设置 MPU6050_setFullScaleAccelRange(MPU6050_ACCEL_FS_2); // 加速度度最大量程 +-2G MPU6050_setSleepEnabled(0); // 进入工作状态 MPU6050_setI2CMasterModeEnabled(0); // 不让MPU6050 控制AUXI2C MPU6050_setI2CBypassEnabled(0); // 主控制器的I2C与 MPU6050的AUXI2C 直通关闭 } /************************************************************************** Function: Initialization of DMP in mpu6050 Input : none Output : none 函数功能:MPU6050内置DMP的初始化 入口参数:无 返回 值:无 **************************************************************************/ void DMP_Init(void) { uint8_t resetflag = 0; uint8_t temp[1] = {0}; i2cRead(0x68, 0x75, 1, temp); printf("mpu_set_sensor complete ......\r\n"); if (temp[0] != 0x68) DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_POR); if (!mpu_init()) { if (!mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL)) printf("mpu_set_sensor complete ......\r\n"); else resetflag = 1; if (!mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL)) printf("mpu_configure_fifo complete ......\r\n"); else resetflag = 1; if (!mpu_set_sample_rate(DEFAULT_MPU_HZ)) printf("mpu_set_sample_rate complete ......\r\n"); else resetflag = 1; if (!dmp_load_motion_driver_firmware()) printf("dmp_load_motion_driver_firmware complete ......\r\n"); else resetflag = 1; if (!dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation))) printf("dmp_set_orientation complete ......\r\n"); else resetflag = 1; if (!dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO | DMP_FEATURE_GYRO_CAL)) printf("dmp_enable_feature complete ......\r\n"); else resetflag = 1; if (!dmp_set_fifo_rate(DEFAULT_MPU_HZ)) printf("dmp_set_fifo_rate complete ......\r\n"); else resetflag = 1; run_self_test(); if (!mpu_set_dmp_state(1)) printf("mpu_set_dmp_state complete ......\r\n"); } else { DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_POR); } if (resetflag) { mpu6050_i2c_sda_unlock(); DL_SYSCTL_resetDevice(DL_SYSCTL_RESET_POR); } } /************************************************************************** Function: Read the attitude information of DMP in mpu6050 Input : none Output : none 函数功能:读取MPU6050内置DMP的姿态信息 入口参数:无 返回 值:无 **************************************************************************/ void Read_DMP(void) { unsigned long sensor_timestamp; unsigned char more; long quat[4]; dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more); // 读取DMP数据 if (sensors & INV_WXYZ_QUAT) { q0 = quat[0] / q30; q1 = quat[1] / q30; q2 = quat[2] / q30; q3 = quat[3] / q30; // 四元数 Roll = asin(-2 * q1 * q3 + 2 * q0 * q2) * 57.3; // 计算出横滚角 Pitch = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2 * q2 + 1) * 57.3; // 计算出俯仰角 Yaw = atan2(2 * (q1 * q2 + q0 * q3), q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3) * 57.3; // 计算出偏航角 } } /************************************************************************** Function: Read mpu6050 built-in temperature sensor data Input : none Output : Centigrade temperature 函数功能:读取MPU6050内置温度传感器数据 入口参数:无 返回 值:摄氏温度 **************************************************************************/ int Read_Temperature(void) { float Temp; Temp = (I2C_ReadOneByte(devAddr, MPU6050_RA_TEMP_OUT_H) << 8) + I2C_ReadOneByte(devAddr, MPU6050_RA_TEMP_OUT_L); if (Temp > 32768) Temp -= 65536; // 数据类型转换 Temp = (36.53 + Temp / 340) * 10; // 温度放大十倍存放 return (int)Temp; } //------------------End of File----------------------------
最新发布
07-22
<think>嗯,用户的问题是关于MPU6050的Yaw值在OLED上停止更新的原因分析和解决方案。这个问题很具体,涉及到嵌入式系统中的传感器数据处理和显示问题。用户可能正在做一个智能车或者机器人项目,遇到了传感器数据突然停止更新的故障。 从用户提供的引用材料来看,有几个关键点值得注意: 1. 用户使用了STM32F103C8T6作为主控芯片,通过I2C连接MPU6050和OLED(引用3) 2. 用户采用了状态机设计,每次转弯后都会重新初始化MPU6050(引用1) 3. 用户提到了Yaw1变量用于缓解零飘问题(引用1) 4. MPU6050的参考点是初始化时的位置(引用2) 可能的原因分析: 首先想到的是I2C通信故障。因为MPU6050和OLED共享I2C总线,当OLED持续刷新时可能会占用总线导致MPU6050数据读取失败。特别是如果使用了阻塞式读取而没有超时处理的话,程序可能会卡死在I2C读取函数里。 其次是DMP数据处理问题。MPU6050的DMP(数字运动处理器)负责解算姿态数据,如果DMP缓冲区溢出或者配置不当,可能导致数据更新停止。用户提到在状态转换时重新初始化传感器,这个操作本身可能带来风险——如果初始化过程不完整,DMP可能进入错误状态。 堆栈溢出也是个常见问题。姿态解算需要较多计算资源,如果任务堆栈设置不足,可能导致OLED刷新任务崩溃。特别是当使用FreeRTOS等RTOS时,这个问题更常见。 解决方案方面: 1. 建议先检查I2C总线状态,添加错误处理机制 2. 优化DMP初始化流程,避免不必要的重复初始化 3. 增加传感器数据校验,比如检查数据包计数器是否连续 4. 调整任务优先级和堆栈大小 5. 添加看门狗机制确保系统能够从故障中恢复 用户可能还需要注意电源稳定性问题。MPU6050对电源波动比较敏感,电压不稳可能导致芯片工作异常。可以在代码中添加电源电压监测,或者硬件上增加滤波电容。 这个问题确实很典型,很多人在使用MPU6050时都会遇到。我记得自己第一次用的时候也卡在类似问题上好几天。用户能明确描述出"Yaw值停止更新"这个现象很好,说明已经做了初步的故障定位。接下来需要系统地排查各个可能环节。</think>以下是MPU6050的Yaw值在OLED上停止更新的可能原因及解决方案,结合嵌入式系统特性和引用内容分析: ### 可能原因分析 1. **I²C通信阻塞** - MPU6050与OLED共享I²C总线(引用[3]),若未正确处理总线冲突,可能导致通信死锁。 - **典型表现**:I²C超时错误后程序卡死,Yaw值停止更新。 2. **DMP数据处理异常** - 状态机中频繁初始化MPU6050(引用[1])可能破坏DMP内部状态: ```c IIC_Init(); MPU6050_initialize(); // 硬件初始化 DMP_Init(); // DMP固件重载 Yaw1 = 0; // 清零缓存的Yaw值 ``` - **风险**:重复初始化可能引发DMP缓冲区溢出或寄存器配置错误。 3. **堆栈溢出** - DMP解算和OLED刷新消耗较大内存(引用[3]),若任务堆栈不足会导致系统崩溃。 4. **传感器数据异常** - 剧烈运动导致陀螺仪量程溢出(±2000dps默认值),传感器进入错误状态(引用[4])。 5. **硬件问题** - 电源波动(如电机干扰)使MPU6050工作异常(引用[4])。 --- ### 解决方案 #### 1. 优化I²C通信(关键步骤) ```c // 增加总线错误恢复机制 HAL_StatusTypeDef ret = HAL_I2C_Master_Receive(&hi2c1, MPU6050_ADDR, data, 14, 100); if(ret != HAL_OK) { I2C_ClearBus(hi2c1); // 自定义总线复位函数 MX_I2C1_Init(); // 重新初始化I²C外设 } ``` #### 2. 修正DMP初始化逻辑 - **避免频繁初始化**:仅在系统启动时初始化一次DMP - **添加DMP状态检查**: ```c if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more) != 0) { dmp_reset_fifo(); // 重置FIFO而非重新初始化 } ``` #### 3. 内存优化 - 增大任务堆栈(至少增加25%) - 使用静态内存分配: ```c static float q[4]; // 静态存储四元数 dmp_read_fifo(..., q, ...); ``` #### 4. 传感器容错处理 ```c // 检查陀螺仪量程 if(abs(gyro[0])>2000 || abs(gyro[1])>2000 || abs(gyro[2])>2000) { mpu_reset_fifo(); // 重置数据流 } ``` #### 5. 硬件改进 - MPU6050的VCC引脚并联100μF电容 - I²C总线加10kΩ上拉电阻(SCL/SDA到3.3V) - 电机驱动电路与传感器电源分离 --- ### 调试建议 1. **添加监控点** 在OLED刷新函数前插入LED指示灯,观察是否持续执行: ```c HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 调试LED OLED_ShowYaw(yaw); // 显示Yaw值 ``` 2. **记录错误日志** 通过串口输出DMP错误码: ```c uint8_t err = dmp_get_state(); if(err) printf("DMP ERROR: 0x%02X\n", err); ``` 3. **参考点验证**(引用[2]) 静止时检查Yaw值是否归零,确认初始化位置基准正确。 > **关键提示**:避免在状态切换时重复初始化DMP(引用[1]),这可能导致DMP固件加载失败。建议在系统启动时仅初始化一次,状态切换时仅重置FIFO和角度偏移。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值