本帖最后由 李皇谛 于 2024-2-17 13:48 编辑
你那个说明的软件复位按钮放在了P5.4引脚上,这时候你要在ISP编程界面里面把红色所示的钩去掉,那样就能通过串口写ISP复位了。
如果不行的话,下载用于STC32的USB固件库,通过HID模式或CDC模式二选一(建议直接使用CDC模式),在自己的工程文件中导入“usb.h”以及选中的一种固件库(不能同时导入2个固件库,因为有设备标识符冲突)。
在“usb.h”或者“main.c”里面,把你设置好的单片机频率以Hz为单位定义到“MAIN_Fosc”里面(因为USB固件库要用这个频率调整USB端口)
#define MAIN_Fosc 52000000L //选中的STC32F频率为52MHz 复制代码
在自己的工程文件里记住用于直接进入ISP模式的口令:(我没改过,用默认值了)
char *USER_DEVICEDESC = NULL; //设备描述符
char *USER_PRODUCTDESC = NULL; //产品描述符
char *USER_STCISPCMD = "@STCISP#"; //设置自动复位到ISP区的用户接口命令 复制代码
紧接着配置好P3.0和P3.1的工作模式,全部工作在高阻输入模式下。并且启用USB用时钟,随后配置好USB的工作模式。
请保证你的工程没有其它硬件使用P3.0和P3.1
void main()
{ //……
//管脚全部重配置为准双向口
//P0M1=0; P0M0=0; P1M1=0; P1M0=0; P2M1=0; P2M0=0; P3M1=0; P3M0=0;
//P4M1=0; P4M0=0; P5M1=0; P5M0=0; P6M1=0; P6M0=0; P7M1=0; P7M0=0;
P3M0 &= ~0x03; P3M1 |= 0x03; //P3.0和P3.1高阻,USB要用到
IRC48MCR = 0x80; while (!(IRC48MCR & 0x01)); //加USB时钟
USBCLK = 0x00; USBCON = 0x90; usb_init();
//…… 复制代码
以下为USB-CDC简单范例程序,如果你没有头绪,可以直接添加:
while(1){ delay_ms(1);
if(DeviceState==DEVSTATE_CONFIGURED) LED_P35=0; else continue;//如果USB就绪就点P3.5的灯,否则硬等
if(bUsbInBusy) {/*等待USB发数据时需要执行的程序,如果没有将整行删除*/};
if(bUsbOutReady)
{//……
//在这里执行从电脑发数据到单片机完毕后的程序
USB_SendData(UsbOutBuffer,OutNumber); //发内容到电脑,其中“UsbOutBuffer”为收到来自电脑的数据,“OutNumber”为收到数据的字节大小
usb_OUT_done(); //检查电脑是否收到单片机发的数据
}
复制代码
烧写程序之后,单片机连接电脑。
如果你用了HID固件,使用HID助手连接制造商编号(VID)为“34BF”的设备(HID\VID_34BF\PID_****),通过中断输入输出当串口使用。
如果你用了CDC固件,直接使用串口助手找到STC单片机的串口。
这时候,不论是使用了串口还是HID调试器,只要输入ISP复位指令(手动输入或者“收到用户命令后复位到ISP监控程序区”),单片机就会直接复位到ISP模式,显示一个HID设备。
*也就是说,不要在你的工程里面使用ISP复位口令用作数据。
这样的话,就可以直接烧写程序或者检查单片机工作选项了,完成一次ISP操作(写程序或查单片机配置其一)就会复位回用户程序。
如果你用的是串口,建议把“下次使用STC-HID接口进行下载”打钩。
如果不想这么麻烦,可以把“每次下载前都先发送自定义指令”打钩。写程序的时候还要检查自己有没有用错串口或者HID。
以下为长按P3.2手动进入ISP的程序代码(因为我的核心板里P3.2不连接按钮,同时有其它用途):
void KeyResetScan(void); //子函数预注册
//……
void main() //main函数往下,没有注册的子函数不会得到执行,除非你使用了"main.h"预定义
{ //……
while(1){
KeyResetScan();
}
//……
}
void KeyResetScan(void)
{ if(!P32)
{ if(!Key_Flag)
{ Key_cnt++;
if(Key_cnt >= 1000) //连续1000ms有效按键检测
{ Key_Flag = 1; //设置按键状态,防止重复触发
USBCON = 0x00; //清除USB设置
USBCLK = 0x00; //USB端口停振
IRC48MCR = 0x00; //停用内部USB时钟
delay_ms(10); //等配置完成
IAP_CONTR = 0x60; //触发软件复位,从ISP开始执行
while (1); }
}
}
else
{Key_cnt = 0;Key_Flag = 0;}
} 复制代码
以下为我修改了“usb.h”之后的程序,可自行剪裁复制:
/* READ ME 阅读前注意事项
*基本概念科普:
*STC系列实验板可以直接添加USB接口相关固件库,可在手里没有串口调试器的情况下直接用USB接口进行程序调试与写入。
*单片机具有两种USB驱动模式:USB-HID(人体工程学输入设备)和USB-CDC(数据通信抽象设备)
*HID接口可用于模拟鼠标、键盘、游戏手柄、压枪宏、模拟游戏用特种手柄等等。
*CDC接口可用于电脑跟单片机直接通信并以串口形式交换数据,而且通信速度可以快过普通串口。
*以下操作可能无法使用USB接口:
**用于跟其他单片机的通信
**使用了不正确的模式进行通信(比如CDC模式用了HID接口)
*文件使用事项:
**需要先在工程上导入USB通信用预制库才能用USB功能,一个工程只能使用一个类似预制库文件。
“stc_usb_cdc_32f.LIB”(USB-CDC协议)或“stc_usb_hid_32f.LIB”
*常见解决方法:
*Windows10无法识别单片机,属性提示“驱动程序未经签名”?
**从相同操作系统版本复制usbscan.sys文件到C:\Windows\System32\drivers目录
**使用特殊启动模式:禁用驱动程序强制签名
*无法识别的USB设备?
**若上次烧写好的程序不占用P3.0和P3.1的串口,把串口拔了,直接写默认ISP代码进行USB通信。
**若上次烧写的程序没使用正确的USB驱动(stc_usb_***_32f.LIB)或者无法被识别,只能用串口写程序。
*各种Syntax错误?
**把需要编译但是扩展折叠条件的行添加 #if 1
**把不需要编译的改为#if 0
*我没有P3.2拿来开机复位,怎么写程序?
**直接在串口或者HID的中断区输入“USER_STCISPCMD”内存的接口命令会让单片机自动复位到ISP区域,
**这时候会显示“STC-USB Writer(HID1)”。
*设备重置失败?
**请为“MAIN_Fosc”定义使用的系统时钟。
*/
#ifndef __USB_H__
#define __USB_H__
/**需要提前在主程序声明的全局变量:
char *USER_DEVICEDESC = NULL; //设备描述符
char *USER_PRODUCTDESC = NULL; //产品描述符
char *USER_STCISPCMD = "@STCISP#"; //设置自动复位到ISP区的用户接口命令
#define MAIN_Fosc 52000000L //USB固件库自动调节时间需要的频率(不调节频率,使用52MHz默认值)
//使用串口“printf”打印信息需屏蔽以下两个定义
//#define PRINTF_SEGLED //printf输出重定向到ISP下载软件中的7段数码管
//#define PRINTF_HID //printf输出直接重定向到USB HID接口
*/
#ifndef NULL
#define NULL ((void *) 0)
#endif
#if 1 //USB状态
#define DEVSTATE_ATTACHED 0 //已插入到接口
#define DEVSTATE_POWERED 1 //已确认通电
#define DEVSTATE_DEFAULT 2 //已进入初始化状态
#define DEVSTATE_ADDRESS 3 //已分配从机地址
#define DEVSTATE_CONFIGURED 4 //已配置工作模式(准备就绪)
#define DEVSTATE_SUSPENDED 5 //遭到挂起
#endif //USB状态
void usb_init();//初始化USB接口
//void usb_IN(); //USB HID
//void usb_IN(WORD size); //USB CDC
void usb_OUT_done(); //检查数据是否发送完毕
void USB_SendData(BYTE *dat, int size); //单片机向连接设备发数据
//ISP虚拟示波器不能使用预置的交互函数。
#if 1 //STC ISP虚拟用户界面交互函数
// 8位7段带点数码管
int SEG7_ShowString(const char *fmt, ...); //显示字符串
void SEG7_ShowLong(long n, char radix); //显示长整数
void SEG7_ShowFloat(float f); //显示浮点数
void SEG7_ShowCode(BYTE *cod); //显示原始段码
// 虚拟单片机引脚IO口
void LED40_SendData(BYTE *dat, BYTE size); //DIP40的单片机LED口
void LED64_SendData(BYTE *dat, BYTE size); //DIP64的单片机LED口
// 12864型LCD(主控为ST7920)
void LCD12864_DisplayOff(); //快速关闭显示屏
void LCD12864_DisplayOn(); //快速打开显示屏
void LCD12864_CursorOff(); //隐藏光标
void LCD12864_CursorOn(); //显示光标(16×16像素)
void LCD12864_CursorMoveLeft(); //光标左移(16像素)
void LCD12864_CursorMoveRight(); //光标右移(16像素)
void LCD12864_CursorReturnHome(); //光标回位(左上角)
void LCD12864_ScrollLeft(); //向左滚动(16像素)
void LCD12864_ScrollRight(); //向右滚动(16像素)
void LCD12864_ScrollUp(BYTE line); //向上滚动(line为移动行数)
void LCD12864_AutoWrapOff(); //关闭自动换行
void LCD12864_AutoWrapOn(); //启用自动换行
void LCD12864_ReverseLine(BYTE line); //将指定行负色(line为第几行)
void LCD12864_DisplayClear(); //清屏
void LCD12864_ShowString(BYTE x, BYTE y, char *str); //显示字符串
//(主要! x和y为起始位置,str为字符串)
void LCD12864_ShowPicture(BYTE x, BYTE y, BYTE cx, BYTE cy, BYTE *dat); //显示图片
//(x和y为起始位置,cx为使用行数,cy为使用列数,dat为目标图片)
// 12864型OLED(主控为SSD1306)
void OLED12864_DisplayOff();
void OLED12864_DisplayOn();
void OLED12864_DisplayContent();
void OLED12864_DisplayEntire();
void OLED12864_HorizontalMirror();
void OLED12864_VerticalMirror();
void OLED12864_DisplayReverse();
void OLED12864_SetContrast(BYTE bContrast);
void OLED12864_SetAddressMode(BYTE bMode);
void OLED12864_ScrollLeft(BYTE bPageStart, BYTE bPageEnd, WORD nInterval);
void OLED12864_ScrollRight(BYTE bPageStart, BYTE bPageEnd, WORD nInterval);
void OLED12864_ScrollUp(BYTE bPageStart, BYTE bPageEnd, WORD nInterval);
void OLED12864_ScrollStart();
void OLED12864_ScrollStop();
void OLED12864_ShowPicture(BYTE x, BYTE y, BYTE cx, BYTE cy, BYTE *dat);
#endif //STC ISP调试器交互函数
int printf_hid (const char *fmt, ...); //向HID调试界面打印内容
#if defined PRINTF_SEGLED
#define printf SEG7_ShowString
#elif defined PRINTF_HID
#define printf printf_hid
#endif
#if 1 //USB基本设备寄存器
extern BYTE xdata UsbFeatureBuffer[64]; //USB设备标识符缓冲器(有默认值)
extern BYTE xdata UsbInBuffer[64]; //单片机发上位机的数据缓冲器
extern BYTE xdata UsbOutBuffer[64]; //上位机发单片机的数据缓冲器
extern bit bUsbFeatureReady; //状态:USB设备标识符缓冲器已就绪
extern bit bUsbInBusy; //状态:正在向上位机发送数据
extern bit bUsbOutReady; //状态:已收到上位机发单片机的数据
extern BYTE DeviceState; //状态:USB设备配置状态
extern BYTE OutNumber; //统计:USB收到数据大小(至多64字节)
#endif
#endif
复制代码
当然,你也可以通过下面一个官方帖子找到CDC用例程: