keil硬仿卡死在while(RCC_GetSYSCLKSource() != 0x08);

本文介绍了一个关于STM32微控制器中倍频配置的问题,通过调整PLL配置解决了硬仿跑飞现象,并探讨了可能的原因。

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

void RCC_Configuration(void)
{
	RCC_DeInit();
	RCC_HSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)== RESET);
	RCC_HCLKConfig(RCC_SYSCLK_Div1);
	RCC_PCLK2Config(RCC_HCLK_Div1);
	RCC_PCLK1Config(RCC_HCLK_Div2);
	RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
	RCC_PLLCmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
	while(RCC_GetSYSCLKSource() != 0x08);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
}

使用内部晶振,倍频至最高频率64M

硬仿跑飞,停留在

0xFFFFFFFE 0000      MOVS     r0,r0; #36]  ; @0x080001B4

有解释说是ram溢出,但此程序只开了1个定时与1个串口,不存在溢出问题

单步发现是停留在

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);

随手改了下倍频数就好了

RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_8);


我想做一个宠物智能投喂系统的仿真,现在我设计l一个stm32f103c6单片机,其PA1连接了compim的RXD,PA2连接了TXD,PB0、PB1连接了发光二极管,发光二极管用来模拟电机转动状态,我创建了一个mfc程序(PCMFCDLG),添加了5个Combo Box控件分别用来选择端口号(控件类,m_cbPort)、波特率(控件类,m_cbBaud)、校验位(控件类,m_cbParity)、数据位(控件类,m_cbDate)以及停止位(控件类,m_cbStop),4个按钮控件分别用来打开串口连接stm32单片机、关闭串口、立即投喂、定时投喂,3个Edit control控件(value类,m_strTime1/2/3)用来定时3个时间点实现定时投喂,最后还有一个List Box(控件类,m_listStatus)用来显示执行状态,在PC机与单片机没有建立连接的时候除了连接按钮,其他按钮都不能点击,在定时按钮没有按下的时候edit control控件不能输入,在单片机执行完相应操作后,会返还给PC机信息,然后显示在list box里面如mfc界面点击立即投喂,单片机执行完操作后返回给pc端mfc界面一个标志,告诉pc端操作已完成,然后在mfc界面的list里面显示对应操作已完成。 请你根据我的需求帮我写出所有的代码,包括mfc的PCMFC.h代码文件以及PCMFC.cpp代码文件和SerialPort.h代码文件以及SerialPort.c代码文件,和keil里面的相应代码文件。 MFC 代码文件: SerialPort.h cpp #pragma once #include <windows.h> #include <vector> #include <afxwin.h> #include <afxstr.h> class CSerialPort { public: CSerialPort(); ~CSerialPort(); bool InitPort(CWnd* pOwner, LPCTSTR port, UINT baud, BYTE parity, BYTE databits, BYTE stopbits); bool OpenListenThread(); void ClosePort(); bool WriteToPort(const BYTE* buffer, DWORD length); bool IsConnected() const { return m_hComm != INVALID_HANDLE_VALUE; } static const UINT WM_COMM_ERR = WM_USER + 1; static const UINT WM_COMM_RECEIVED = WM_USER + 2; private: HANDLE m_hComm; bool m_bThreadRunning; CWnd* m_pOwner; CRITICAL_SECTION m_cs; static DWORD WINAPI ListenThread(LPVOID lpParam); void ProcessReceivedData(const BYTE* buffer, DWORD length); void ReportError(const CString& msg); void PurgeComm(); }; SerialPort.cpp cpp #include "pch.h" #include "SerialPort.h" CSerialPort::CSerialPort() : m_hComm(INVALID_HANDLE_VALUE) , m_bThreadRunning(false) , m_pOwner(nullptr) { InitializeCriticalSection(&m_cs); } CSerialPort::~CSerialPort() { ClosePort(); DeleteCriticalSection(&m_cs); } bool CSerialPort::InitPort(CWnd* pOwner, LPCTSTR port, UINT baud, BYTE parity, BYTE databits, BYTE stopbits) { m_pOwner = pOwner; // 打开串口 m_hComm = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (m_hComm == INVALID_HANDLE_VALUE) { ReportError(_T("无法打开串口")); return false; } // 设置串口缓冲区 if (!SetupComm(m_hComm, 1024, 1024)) { ReportError(_T("设置串口缓冲区失败")); CloseHandle(m_hComm); m_hComm = INVALID_HANDLE_VALUE; return false; } // 配置串口参数 DCB dcb = { 0 }; dcb.DCBlength = sizeof(DCB); if (!GetCommState(m_hComm, &dcb)) { ReportError(_T("获取串口状态失败")); CloseHandle(m_hComm); m_hComm = INVALID_HANDLE_VALUE; return false; } dcb.BaudRate = baud; dcb.ByteSize = databits; dcb.Parity = parity; dcb.StopBits = stopbits; dcb.fBinary = TRUE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; if (!SetCommState(m_hComm, &dcb)) { ReportError(_T("设置串口参数失败")); CloseHandle(m_hComm); m_hComm = INVALID_HANDLE_VALUE; return false; } // 设置超时参数 COMMTIMEOUTS timeouts = { 0 }; timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (!SetCommTimeouts(m_hComm, &timeouts)) { ReportError(_T("设置串口超时失败")); CloseHandle(m_hComm); m_hComm = INVALID_HANDLE_VALUE; return false; } PurgeComm(); return true; } void CSerialPort::PurgeComm() { if (m_hComm != INVALID_HANDLE_VALUE) { ::PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR); } } bool CSerialPort::OpenListenThread() { if (!IsConnected() || !m_pOwner) return false; PurgeComm(); m_bThreadRunning = true; HANDLE hThread = CreateThread(NULL, 0, ListenThread, this, 0, NULL); if (hThread == NULL) { m_bThreadRunning = false; return false; } CloseHandle(hThread); return true; } DWORD WINAPI CSerialPort::ListenThread(LPVOID lpParam) { CSerialPort* pThis = (CSerialPort*)lpParam; BYTE buffer[1024]; DWORD bytesRead = 0; OVERLAPPED ov = { 0 }; ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (ov.hEvent == NULL) { pThis->ReportError(_T("创建事件对象失败")); return 1; } while (pThis->m_bThreadRunning) { BOOL bReadStatus = ReadFile(pThis->m_hComm, buffer, sizeof(buffer), &bytesRead, &ov); if (!bReadStatus) { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) { WaitForSingleObject(ov.hEvent, INFINITE); if (GetOverlappedResult(pThis->m_hComm, &ov, &bytesRead, FALSE)) { if (bytesRead > 0) { pThis->ProcessReceivedData(buffer, bytesRead); } } } else { pThis->ReportError(_T("读取串口数据失败")); break; } } else { if (bytesRead > 0) { pThis->ProcessReceivedData(buffer, bytesRead); } } } CloseHandle(ov.hEvent); return 0; } void CSerialPort::ProcessReceivedData(const BYTE* buffer, DWORD length) { EnterCriticalSection(&m_cs); if (m_pOwner && m_pOwner->GetSafeHwnd()) { BYTE* pData = new BYTE[length]; memcpy(pData, buffer, length); m_pOwner->PostMessage(WM_COMM_RECEIVED, (WPARAM)length, (LPARAM)pData); } LeaveCriticalSection(&m_cs); } void CSerialPort::ReportError(const CString& msg) { EnterCriticalSection(&m_cs); if (m_pOwner && m_pOwner->GetSafeHwnd()) { CString* pMsg = new CString(msg); m_pOwner->PostMessage(WM_COMM_ERR, (WPARAM)pMsg, 0); } LeaveCriticalSection(&m_cs); } void CSerialPort::ClosePort() { m_bThreadRunning = false; Sleep(100); if (IsConnected()) { PurgeComm(); CloseHandle(m_hComm); m_hComm = INVALID_HANDLE_VALUE; } m_pOwner = nullptr; } bool CSerialPort::WriteToPort(const BYTE* buffer, DWORD length) { if (!IsConnected()) { ReportError(_T("串口未打开")); return false; } DWORD bytesWritten; OVERLAPPED ov = { 0 }; ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (ov.hEvent == NULL) { ReportError(_T("创建事件对象失败")); return false; } if (!WriteFile(m_hComm, buffer, length, &bytesWritten, &ov)) { DWORD err = GetLastError(); if (err == ERROR_IO_PENDING) { if (!GetOverlappedResult(m_hComm, &ov, &bytesWritten, TRUE)) { CloseHandle(ov.hEvent); ReportError(_T("写入串口失败 (等待)")); return false; } } else { CloseHandle(ov.hEvent); ReportError(_T("写入串口失败 (立即)")); return false; } } CloseHandle(ov.hEvent); return bytesWritten == length; } PCMFCDlg.h cpp #pragma once #include "SerialPort.h" #include "afxdialogex.h" class CPCMFCDlg : public CDialogEx { public: CPCMFCDlg(CWnd* pParent = nullptr); #ifdef AFX_DESIGN_TIME enum { IDD = IDD_PCMFC_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); virtual BOOL OnInitDialog(); HICON m_hIcon; DECLARE_MESSAGE_MAP() public: CComboBox m_cbPort; CComboBox m_cbBaud; CComboBox m_cbParity; CComboBox m_cbData; CComboBox m_cbStop; CListBox m_listStatus; CString m_strTime1; CString m_strTime2; CString m_strTime3; CSerialPort m_SerialPort; BOOL m_bConnected; UINT_PTR m_nTimerID; BOOL m_bTimerEnabled; CByteArray m_RecvBuffer; // 接收数据缓冲区 CCriticalSection m_csRecv; // 缓冲区临界区 BOOL ValidateTimeFormat(CString strTime); void SendFeedCommand(); void OpenSerialPort(); void CloseSerialPort(); void AddStatusMessage(CString message); void EnableControls(BOOL bEnable); void ParseResponse(const BYTE* buffer, DWORD length); void ProcessRecvBuffer(); afx_msg void OnBnClickedButtonOpen(); afx_msg void OnBnClickedButtonClose(); afx_msg void OnBnClickedButtonNowfeed(); afx_msg void OnBnClickedButtonTimefeed(); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg LRESULT OnCommErr(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnCommReceived(WPARAM wParam, LPARAM lParam); afx_msg void OnDestroy(); }; PCMFCDlg.cpp cpp #include "pch.h" #include "framework.h" #include "PCMFC.h" #include "PCMFCDlg.h" #include "afxdialogex.h" #include <ctime> #ifdef _DEBUG #define new DEBUG_NEW #endif CPCMFCDlg::CPCMFCDlg(CWnd* pParent) : CDialogEx(IDD_PCMFC_DIALOG, pParent), m_strTime1(_T("08:00")), m_strTime2(_T("12:00")), m_strTime3(_T("18:00")), m_bConnected(FALSE), m_nTimerID(0), m_bTimerEnabled(FALSE) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CPCMFCDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO_PORT, m_cbPort); DDX_Control(pDX, IDC_COMBO_BAUD, m_cbBaud); DDX_Control(pDX, IDC_COMBO_PARITY, m_cbParity); DDX_Control(pDX, IDC_COMBO_DATA, m_cbData); DDX_Control(pDX, IDC_COMBO_STOP, m_cbStop); DDX_Control(pDX, IDC_LIST, m_listStatus); DDX_Text(pDX, IDC_EDIT_TIME1, m_strTime1); DDX_Text(pDX, IDC_EDIT_TIME2, m_strTime2); DDX_Text(pDX, IDC_EDIT_TIME3, m_strTime3); } BEGIN_MESSAGE_MAP(CPCMFCDlg, CDialogEx) ON_BN_CLICKED(IDC_BUTTON_OPEN, &CPCMFCDlg::OnBnClickedButtonOpen) ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CPCMFCDlg::OnBnClickedButtonClose) ON_BN_CLICKED(IDC_BUTTON_NOWFEED, &CPCMFCDlg::OnBnClickedButtonNowfeed) ON_BN_CLICKED(IDC_BUTTON_TIMEFEED, &CPCMFCDlg::OnBnClickedButtonTimefeed) ON_WM_TIMER() ON_WM_DESTROY() ON_MESSAGE(CSerialPort::WM_COMM_ERR, &CPCMFCDlg::OnCommErr) ON_MESSAGE(CSerialPort::WM_COMM_RECEIVED, &CPCMFCDlg::OnCommReceived) END_MESSAGE_MAP() void CPCMFCDlg::AddStatusMessage(CString message) { CTime currentTime = CTime::GetCurrentTime(); CString timestamp = currentTime.Format(_T("[%H:%M:%S] ")); m_listStatus.AddString(timestamp + message); m_listStatus.SetCurSel(m_listStatus.GetCount() - 1); } void CPCMFCDlg::EnableControls(BOOL bEnable) { GetDlgItem(IDC_BUTTON_CLOSE)->EnableWindow(bEnable); GetDlgItem(IDC_BUTTON_NOWFEED)->EnableWindow(bEnable); GetDlgItem(IDC_BUTTON_TIMEFEED)->EnableWindow(bEnable); GetDlgItem(IDC_EDIT_TIME1)->EnableWindow(bEnable && m_bTimerEnabled); GetDlgItem(IDC_EDIT_TIME2)->EnableWindow(bEnable && m_bTimerEnabled); GetDlgItem(IDC_EDIT_TIME3)->EnableWindow(bEnable && m_bTimerEnabled); } BOOL CPCMFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // 初始化串口选项 for (int i = 1; i <= 16; ++i) { CString port; port.Format(_T("COM%d"), i); m_cbPort.AddString(port); } m_cbPort.SetCurSel(0); m_cbBaud.AddString(_T("1200")); m_cbBaud.AddString(_T("2400")); m_cbBaud.AddString(_T("4800")); m_cbBaud.AddString(_T("9600")); m_cbBaud.AddString(_T("19200")); m_cbBaud.AddString(_T("38400")); m_cbBaud.AddString(_T("57600")); m_cbBaud.AddString(_T("115200")); m_cbBaud.SetCurSel(3); // 默认9600波特率 m_cbParity.AddString(_T("None")); m_cbParity.AddString(_T("Odd")); m_cbParity.AddString(_T("Even")); m_cbParity.SetCurSel(0); // 默认无校验 m_cbData.AddString(_T("5")); m_cbData.AddString(_T("6")); m_cbData.AddString(_T("7")); m_cbData.AddString(_T("8")); m_cbData.SetCurSel(3); // 默认8数据位 m_cbStop.AddString(_T("1")); m_cbStop.AddString(_T("1.5")); m_cbStop.AddString(_T("2")); m_cbStop.SetCurSel(0); // 默认1停止位 EnableControls(FALSE); AddStatusMessage(_T("系统启动完成")); AddStatusMessage(_T("请设置串口参数并打开连接")); return TRUE; } void CPCMFCDlg::OnDestroy() { if (m_nTimerID) { KillTimer(m_nTimerID); m_nTimerID = 0; } CloseSerialPort(); CDialogEx::OnDestroy(); } LRESULT CPCMFCDlg::OnCommErr(WPARAM wParam, LPARAM lParam) { CString* pMsg = (CString*)wParam; if (pMsg) { AddStatusMessage(_T("串口错误: ") + *pMsg); delete pMsg; } return 0; } LRESULT CPCMFCDlg::OnCommReceived(WPARAM wParam, LPARAM lParam) { DWORD length = (DWORD)wParam; BYTE* buffer = (BYTE*)lParam; if (buffer && length > 0) { // 将数据添加到接收缓冲区 m_csRecv.Lock(); for (DWORD i = 0; i < length; i++) { m_RecvBuffer.Add(buffer[i]); } m_csRecv.Unlock(); // 处理接收缓冲区 ProcessRecvBuffer(); delete[] buffer; } return 0; } void CPCMFCDlg::ProcessRecvBuffer() { m_csRecv.Lock(); // 查找完整数据包 (4字节: AA CMD STATUS 55) int bufferSize = m_RecvBuffer.GetSize(); int i = 0; while (i <= bufferSize - 4) { if (m_RecvBuffer[i] == 0xAA && m_RecvBuffer[i+3] == 0x55) { // 提取完整数据包 BYTE cmd = m_RecvBuffer[i+1]; BYTE status = m_RecvBuffer[i+2]; // 处理命令 switch(cmd) { case 0x01: // 喂食命令 AddStatusMessage(status == 0x00 ? _T("设备响应: 喂食成功") : _T("设备响应: 喂食失败")); break; default: AddStatusMessage(_T("收到未知命令响应")); break; } // 从缓冲区移除已处理的数据 for (int j = 0; j < 4; j++) { m_RecvBuffer.RemoveAt(i); } bufferSize = m_RecvBuffer.GetSize(); } else { i++; } } m_csRecv.Unlock(); } void CPCMFCDlg::OpenSerialPort() { if (m_bConnected) { AddStatusMessage(_T("串口已连接,无需重复打开")); return; } CString strPort, strBaud; m_cbPort.GetWindowText(strPort); m_cbBaud.GetWindowText(strBaud); int baudRate = _ttoi(strBaud); int parity = m_cbParity.GetCurSel(); int dataBits = m_cbData.GetCurSel() + 5; int stopBits = m_cbStop.GetCurSel(); if (m_SerialPort.InitPort(this, strPort, baudRate, parity, dataBits, stopBits)) { if (m_SerialPort.OpenListenThread()) { m_bConnected = TRUE; EnableControls(TRUE); AddStatusMessage(_T("串口打开成功: ") + strPort + _T(" @") + strBaud); } else { m_SerialPort.ClosePort(); AddStatusMessage(_T("无法启动监听线程")); } } else { AddStatusMessage(_T("串口打开失败: ") + strPort); } } void CPCMFCDlg::CloseSerialPort() { if (m_bConnected) { m_SerialPort.ClosePort(); m_bConnected = FALSE; EnableControls(FALSE); AddStatusMessage(_T("串口已关闭")); } } BOOL CPCMFCDlg::ValidateTimeFormat(CString strTime) { if (strTime.GetLength() != 5) return FALSE; if (strTime[2] != _T(':')) return FALSE; int hour = _ttoi(strTime.Left(2)); int min = _ttoi(strTime.Mid(3)); return (hour >= 0 && hour < 24 && min >= 0 && min < 60); } void CPCMFCDlg::SendFeedCommand() { if (!m_bConnected) { AddStatusMessage(_T("错误: 串口未连接")); return; } BYTE cmd[] = { 0xAA, 0x01, 0x00, 0x55 }; CString strBytes; for (int i = 0; i < sizeof(cmd); i++) { strBytes.AppendFormat(_T("%02X "), cmd[i]); } AddStatusMessage(_T("发送指令: ") + strBytes); if (m_SerialPort.WriteToPort(cmd, sizeof(cmd))) { AddStatusMessage(_T("喂食指令已发送")); } else { AddStatusMessage(_T("错误: 指令发送失败")); } } void CPCMFCDlg::OnBnClickedButtonOpen() { OpenSerialPort(); } void CPCMFCDlg::OnBnClickedButtonClose() { CloseSerialPort(); } void CPCMFCDlg::OnBnClickedButtonNowfeed() { SendFeedCommand(); } void CPCMFCDlg::OnBnClickedButtonTimefeed() { UpdateData(TRUE); if (!ValidateTimeFormat(m_strTime1) || !ValidateTimeFormat(m_strTime2) || !ValidateTimeFormat(m_strTime3)) { AddStatusMessage(_T("错误: 时间格式无效 (使用 HH:MM 格式)")); return; } if (m_nTimerID) { KillTimer(m_nTimerID); m_nTimerID = 0; m_bTimerEnabled = FALSE; AddStatusMessage(_T("定时喂食已停止")); } else { m_nTimerID = SetTimer(1, 60000, NULL); // 每分钟检查一次 m_bTimerEnabled = TRUE; CString msg; msg.Format(_T("定时喂食已启动: %s, %s, %s"), m_strTime1, m_strTime2, m_strTime3); AddStatusMessage(msg); } EnableControls(m_bConnected); } void CPCMFCDlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { CTime currentTime = CTime::GetCurrentTime(); CString strCurrent = currentTime.Format(_T("%H:%M")); if (strCurrent == m_strTime1) { AddStatusMessage(_T("到达定时喂食时间1: ") + m_strTime1); SendFeedCommand(); } else if (strCurrent == m_strTime2) { AddStatusMessage(_T("到达定时喂食时间2: ") + m_strTime2); SendFeedCommand(); } else if (strCurrent == m_strTime3) { AddStatusMessage(_T("到达定时喂食时间3: ") + m_strTime3); SendFeedCommand(); } } CDialogEx::OnTimer(nIDEvent); } Keil 单片机代码文件: hardware.h c #pragma once #include "stm32f10x.h" // 引脚定义 #define MOTOR_PORT GPIOB #define MOTOR_PIN1 GPIO_Pin_0 #define MOTOR_PIN2 GPIO_Pin_1 // 协议定义 #define CMD_HEADER 0xAA #define CMD_FEED 0x01 #define CMD_END 0x55 // 状态反馈 #define STATUS_OK 0x00 #define STATUS_ERROR 0xFF // 函数声明 void RCC_Configuration(void); void Hardware_Init(void); void Motor_Feed(uint8_t seconds); void SendResponse(uint8_t status, uint8_t cmdType); hardware.c c #include "hardware.h" #include "stm32f10x_gpio.h" #include "stm32f10x_usart.h" #include "stm32f10x_rcc.h" // 系统时钟配置 (使用外部8MHz晶振,PLL到48MHz) void RCC_Configuration(void) { RCC_DeInit(); // 使能外部高速晶振 RCC_HSEConfig(RCC_HSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 配置PLL (8MHz * 6 = 48MHz) RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 设置系统时钟 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); // 设置AHB、APB1和APB2时钟 RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 = 24MHz RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 = 48MHz // 使能外设时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); } // 件初始化 void Hardware_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 配置USART2引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // TX (PA2) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // RX (PA1) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置电机控制引脚 GPIO_InitStructure.GPIO_Pin = MOTOR_PIN1 | MOTOR_PIN2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(MOTOR_PORT, &GPIO_InitStructure); // 配置USART2 (9600, 8N1) 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中断 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); USART_Cmd(USART2, ENABLE); } // 电机控制函数 (模拟喂食动作) void Motor_Feed(uint8_t seconds) { // 正转 (模拟投喂动作) GPIO_SetBits(MOTOR_PORT, MOTOR_PIN1); GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN2); // 延时 (1秒 = 1000毫秒) for(uint8_t i = 0; i < seconds; i++) { for(uint16_t j = 0; j < 1000; j++) { for(uint16_t k = 0; k < 72; k++); // 约1ms延时 } } // 停止电机 GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN1); GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN2); } // 发送响应给PC void SendResponse(uint8_t status, uint8_t cmdType) { uint8_t response[4] = { CMD_HEADER, cmdType, status, CMD_END }; for(uint8_t i = 0; i < 4; i++) { // 等待发送寄存器空 while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); USART_SendData(USART2, response[i]); } } main.c c #include "stm32f10x.h" #include "hardware.h" // 接收缓冲区 uint8_t rxBuffer[4] = {0}; uint8_t rxIndex = 0; int main(void) { // 系统初始化 RCC_Configuration(); Hardware_Init(); // 初始状态: 关闭电机 GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN1); GPIO_ResetBits(MOTOR_PORT, MOTOR_PIN2); while(1) { // 主循环 (低功耗模式) __WFI(); } } // USART2中断服务程序 void USART2_IRQHandler(void) { // 处理接收中断 if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { uint8_t data = USART_ReceiveData(USART2); // 状态机解析协议 switch(rxIndex) { case 0: // 等待帧头 if(data == CMD_HEADER) { rxBuffer[rxIndex++] = data; } break; case 1: // 等待命令 if(data == CMD_FEED) { rxBuffer[rxIndex++] = data; } else { rxIndex = 0; // 无效命令,重置 } break; case 2: // 等待参数 rxBuffer[rxIndex++] = data; break; case 3: // 等待帧尾 if(data == CMD_END) { rxBuffer[rxIndex] = data; // 验证完整指令 if(rxBuffer[0] == CMD_HEADER && rxBuffer[1] == CMD_FEED && rxBuffer[3] == CMD_END) { // 执行喂食操作 (2秒) Motor_Feed(2); // 发送成功响应 SendResponse(STATUS_OK, CMD_FEED); } else { // 发送错误响应 SendResponse(STATUS_ERROR, CMD_FEED); } } rxIndex = 0; // 重置接收状态 break; default: rxIndex = 0; // 异常状态重置 break; } } } Rebuild target 'STM32103' compiling core_cm3.c... assembling startup_stm32f10x_md.s... compiling system_stm32f10x.c... compiling misc.c... compiling stm32f10x_adc.c... compiling stm32f10x_bkp.c... compiling stm32f10x_can.c... compiling stm32f10x_cec.c... compiling stm32f10x_crc.c... compiling stm32f10x_dac.c... compiling stm32f10x_dbgmcu.c... compiling stm32f10x_dma.c... compiling stm32f10x_exti.c... compiling stm32f10x_flash.c... compiling stm32f10x_fsmc.c... compiling stm32f10x_gpio.c... compiling stm32f10x_i2c.c... compiling stm32f10x_iwdg.c... compiling stm32f10x_pwr.c... compiling stm32f10x_rcc.c... compiling stm32f10x_rtc.c... compiling stm32f10x_sdio.c... compiling stm32f10x_spi.c... compiling stm32f10x_tim.c... compiling stm32f10x_usart.c... compiling stm32f10x_wwdg.c... compiling main.c... src\hardware.h(22): warning: #1-D: last line of file ends without a newline void SendResponse(uint8_t status, uint8_t cmdType); src\main.c(81): warning: #1-D: last line of file ends without a newline } src\main.c: 2 warnings, 0 errors compiling stm32f10x_it.c... compiling led.c... compiling delay.c... compiling hardware.c... src\hardware.h(22): warning: #1-D: last line of file ends without a newline void SendResponse(uint8_t status, uint8_t cmdType); src\hardware.c(86): error: #254: type name is not allowed for(uint8_t i = 0; i < seconds; i++) { src\hardware.c(86): error: #65: expected a ";" for(uint8_t i = 0; i < seconds; i++) { src\hardware.c(86): error: #20: identifier "i" is undefined for(uint8_t i = 0; i < seconds; i++) { src\hardware.c(87): error: #254: type name is not allowed for(uint16_t j = 0; j < 1000; j++) { src\hardware.c(87): error: #65: expected a ";" for(uint16_t j = 0; j < 1000; j++) { src\hardware.c(87): error: #20: identifier "j" is undefined for(uint16_t j = 0; j < 1000; j++) { src\hardware.c(88): error: #254: type name is not allowed for(uint16_t k = 0; k < 72; k++); // 约1ms延时 src\hardware.c(88): error: #65: expected a ";" for(uint16_t k = 0; k < 72; k++); // 约1ms延时 src\hardware.c(88): error: #20: identifier "k" is undefined for(uint16_t k = 0; k < 72; k++); // 约1ms延时 src\hardware.c(102): error: #28: expression must have a constant value cmdType, src\hardware.c(103): error: #28: expression must have a constant value status, src\hardware.c(107): error: #254: type name is not allowed for(uint8_t i = 0; i < 4; i++) { src\hardware.c(107): error: #65: expected a ";" for(uint8_t i = 0; i < 4; i++) { src\hardware.c(107): error: #20: identifier "i" is undefined for(uint8_t i = 0; i < 4; i++) { src\hardware.c(112): warning: #1-D: last line of file ends without a newline } src\hardware.c: 2 warnings, 14 errors ".\Objects\project_1.axf" - 14 Error(s), 4 Warning(s). Target not created. Build Time Elapsed: 00:00:17 这是keil代码出现的问题
06-03
/************************************************* 函数名:main.c 功 能 :key 演示程序 时 间 :2019/02/28 作 者 : *************************************************/ //程序思路: //扫描按键并识别按键 //按键去抖用延时,延时采用精确延时函数 #include <stm32f10x.h> #include "delay.h" //延时函数的头文件 #include <mykey.h> #include <adc.h> #include <oled.h> #include "stdio.h" //系统时钟初始化函数 //采用固件库函数方式编程 //pll:选择的倍频数,从2开始, 最大为9 /******************************************************************************* * Function Name : Rcc_Init * Description : RCC配置(使用外部8MHz晶振) * Input : uint32_t,PLL的倍频系数,例如9就是9*8=72M * Output : 无 * Return : 无 *******************************************************************************/ void I2C_Init(void); void Stm32_Clock_Init(u8 pll); float ReadVoltage(void); void DisplayVoltage(float voltage); uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx); void OLED_DisplayString(uint8_t line, uint8_t *str); void Stm32_Clock_Init(u8 pll); int main(void) { ADC_Init(); I2C_Init(); OLED_Init(); Stm32_Clock_Init(9); //系统时钟设置 delay_init(72); //延时初始化 delay_ms(100); while(1) { float voltage = ReadVoltage(); DisplayVoltage(voltage); delay_ms(1000); // 延迟1秒 } } /* LED PE8--PE15 推挽输出 K1 --k3 PA456 要配成内上拉 kUp PA7 要配成内下拉 */ void OLED_DisplayString(uint8_t line, uint8_t *str) { // 设置显示位置 OLED_SetPosition(0, line); while (*str) { OLED_ShowChar(*str++); } } // 读取ADC值并计算电压 float ReadVoltage(void) { uint16_t adc_value = ADC_GetConversionValue(ADC1); float voltage = (adc_value * 3.3) / 4095.0; // 假设VDD为3.3V return voltage; } // 显示电压值 void DisplayVoltage(float voltage) { char buffer[20]; sprintf(buffer, "电压: %.2f V", voltage); OLED_DisplayString(buffer); // 假设存在这样的函数用于显示字符串 } void Stm32_Clock_Init(u8 pll) { ErrorStatus HSEStartUpStatus; /*将外设RCC寄存器重设为缺省值*/ RCC_DeInit(); /*设置外部高速晶振(HSE)*/ RCC_HSEConfig(RCC_HSE_ON); //RCC_HSE_ON——HSE晶振打开(ON) /*等待HSE起振*/ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) //SUCCESS:HSE晶振稳定且就绪 { /*设置AHB时钟(HCLK)*/ RCC_HCLKConfig(RCC_SYSCLK_Div1); //RCC_SYSCLK_Div1——AHB时钟= 系统时钟 /* 设置高速AHB时钟(PCLK2)*/ RCC_PCLK2Config(RCC_HCLK_Div1); //RCC_HCLK_Div1——APB2时钟= HCLK /*设置低速AHB时钟(PCLK1)*/ RCC_PCLK1Config(RCC_HCLK_Div2); //RCC_HCLK_Div2——APB1时钟= HCLK / 2 /*设置FLASH存储器延时时钟周期数*/ FLASH_SetLatency(FLASH_ACR_LATENCY_2);//FLASH_Latency_2 2延时周期 /*选择FLASH预取指缓存的模式*/ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);// 预取指缓存使能 /*设置PLL时钟源及倍频系数*/ //RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLL的输入时钟= HSE时钟频率;RCC_PLLMul_9——PLL输入时钟x 9 switch(pll) { case 2: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_2); break; case 3: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_3); break; case 4: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_4); break; case 5: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_5); break; case 6: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); break; case 7: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7); break; case 8: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_8); break; case 9: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); break; default: RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_2); break; } /*使能PLL */ RCC_PLLCmd(ENABLE); /*检查指定的RCC标志位(PLL准备好标志)设置与否*/ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*设置系统时钟(SYSCLK)*/ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //RCC_SYSCLKSource_PLLCLK——选择PLL作为系统时钟 /* PLL返回用作系统时钟的时钟源*/ while(RCC_GetSYSCLKSource() != 0x08) //0x08:PLL作为系统时钟 { } } } 帮我找错,以下是错误报告 *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'F:\Keil_v5\ARM\ARMCC\Bin' compiling main.c... main.c(68): warning: #223-D: function "OLED_SetPosition" declared implicitly OLED_SetPosition(0, line); main.c(70): warning: #223-D: function "OLED_ShowChar" declared implicitly OLED_ShowChar(*str++); main.c(84): error: #167: argument of type "char *" is incompatible with parameter of type "uint8_t" OLED_DisplayString(buffer); // 鍋囪瀛樺湪杩欐牱鐨勫嚱鏁扮敤浜庢樉绀哄瓧绗︿覆 main.c(84): error: #165: too few arguments in function call OLED_DisplayString(buffer); // 鍋囪瀛樺湪杩欐牱鐨勫嚱鏁扮敤浜庢樉绀哄瓧绗︿覆 main.c: 2 warnings, 2 errors "main.c" - 2 Error(s), 2 Warning(s).
07-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值