初始化仓库

This commit is contained in:
2025-08-31 21:43:17 +08:00
commit be600d0769
45 changed files with 22852 additions and 0 deletions

91
Source/PCA9685_driver.c Normal file
View File

@@ -0,0 +1,91 @@
#include "PCA9685_driver.h"
#include "delay.h"
#if PCA9685_USE_SOFT_IIC == 1
#include "iic_soft.h"
static IIC_Soft_Config config;
#else
#include "iic.h"
#endif
static uint8 has_init = 0;
void pca9685_init()
{
if(has_init) return; // 如果已经初始化过,则直接返回
#if PCA9685_USE_SOFT_IIC == 1
config.scl_pin = PCA9685_SOFT_IIC_SCL_PIN;
config.sda_pin = PCA9685_SOFT_IIC_SDA_PIN;
config.wait_time = 10;
soft_iic_init(&config); // 初始化软件IIC
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, PCA9685_MODE1, 0x00); // 设置PCA9685模式寄存器为正常模式
#else
// 初始化I2C接口
iic_init(IIC_1, 20);
iic_write_reg(PCA9685_I2C_ADDR, PCA9685_MODE1, 0x00); // 设置为正常模式
#endif
pca9685_set_frequency(PCA9685_DEF_FREQ); // 设置默认频率
has_init = 1;
}
void pca9685_deinit()
{
if(!has_init) return; // 如果没有初始化过,则直接返回
has_init = 0; // 标记为未初始化
}
void pca9685_set_frequency(uint16 frequency)
{
// 计算预分频器值
uint8 prescale = 0;
uint8 old_mode1 = 0;
double prescale_value = 0.0;
prescale_value = 6103.515625 / frequency;
if (prescale_value < 3.0) {
prescale = 3; // 最小预分频器值
} else if (prescale_value > 255.0) {
prescale = 255; // 最大预分频器值
} else {
prescale = (uint8)prescale_value; // 正常预分频器值
if (prescale_value - prescale >= 0.5) {
prescale += 1; // 四舍五入
}
}
#if PCA9685_USE_SOFT_IIC == 1
// soft_iic_read_reg(&config, PCA9685_I2C_ADDR, PCA9685_MODE1, &old_mode1); // 读取当前模式寄存器
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, PCA9685_MODE1, (old_mode1 & 0x7F) | 0x10); // 进入睡眠模式
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, PCA9685_PRESCALE, prescale); // 设置预分频器
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, PCA9685_MODE1, old_mode1); // 恢复正常模式
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, PCA9685_MODE1, old_mode1 | 0x80); // 重启PCA9685
#else
// P05 = 0;
// 设置预分频器
// iic_read_reg(PCA9685_I2C_ADDR, PCA9685_MODE1, &old_mode1);
iic_write_reg(PCA9685_I2C_ADDR, PCA9685_MODE1, (old_mode1 & 0x7F) | 0x10); // 进入睡眠模式
iic_write_reg(PCA9685_I2C_ADDR, PCA9685_PRESCALE, prescale);
// 恢复模式寄存器
iic_write_reg(PCA9685_I2C_ADDR, PCA9685_MODE1, old_mode1); // 恢复正常模式
delay_ms(5); // 等待模式寄存器更新
iic_write_reg(PCA9685_I2C_ADDR, PCA9685_MODE1, old_mode1 | 0x80); // 重启PCA9685
// P05 = 1;
#endif
}
void pca9685_set_pwm(uint8 channel, uint16 on, uint16 off)
{
// P05 = 0; // 开始I2C通信
// 设置指定通道的PWM值
#if PCA9685_USE_SOFT_IIC == 1
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, (PCA9685_LED0_ON_L + 4 * channel) & 0xFF, on & 0xFF);
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, (PCA9685_LED0_ON_H + 4 * channel) & 0xFF, (on >> 8) & 0xFF);
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, (PCA9685_LED0_OFF_L + 4 * channel) & 0xFF, off & 0xFF);
soft_iic_write_reg(&config, PCA9685_I2C_ADDR, (PCA9685_LED0_OFF_H + 4 * channel) & 0xFF, (off >> 8) & 0xFF);
#else
iic_write_reg(PCA9685_I2C_ADDR, (PCA9685_LED0_ON_L + 4 * channel) & 0xFF, on & 0xFF);
iic_write_reg(PCA9685_I2C_ADDR, (PCA9685_LED0_ON_H + 4 * channel) & 0xFF, (on >> 8) & 0xFF);
iic_write_reg(PCA9685_I2C_ADDR, (PCA9685_LED0_OFF_L + 4 * channel) & 0xFF, off & 0xFF);
iic_write_reg(PCA9685_I2C_ADDR, (PCA9685_LED0_OFF_H + 4 * channel) & 0xFF, (off >> 8) & 0xFF);
// P05 = 1; // 结束I2C通信
#endif
}

69
Source/button.c Normal file
View File

@@ -0,0 +1,69 @@
#include "button.h"
uint32 button_press_time = 0; // 按钮按下时间计数
static volatile button_status_enum button_status = BUTTON_NO_PRESS; // 按钮LED状态
void button_init()
{
gpio_mode(BUTTON_LED_R, GPO_PP);
gpio_mode(BUTTON_LED_G, GPO_PP);
gpio_mode(BUTTON_LED_O, GPO_PP);
gpio_set_level(BUTTON_LED_R, 0);
gpio_set_level(BUTTON_LED_G, 0);
gpio_set_level(BUTTON_LED_O, 0);
gpio_pull_set(BUTTON_NO_PIN, PULLUP); // 设置按钮引脚
gpio_pull_set(BUTTON_NC_PIN, PULLUP); // 设置按钮引脚
gpio_mode(BUTTON_NO_PIN, GPIO); // 设置按钮引脚为输入模式
gpio_mode(BUTTON_NC_PIN, GPIO); // 设置按钮引脚为输入模式
// PINIPH |= 0x01;
// PINIPL |= 0x01;
// P0IM0 &= 0x3F;
// P0IM1 &= 0x3F;
// P0INTE |= 0xC0;
}
void button_1ms_callback()
{
if(gpio_get_level(BUTTON_NO_PIN) == 0)
{
button_press_time ++;
if(button_press_time >= 10000) // 防止溢出
{
button_press_time = 10000; // 限制最大值
}
}
else if(gpio_get_level(BUTTON_NC_PIN) == 0)
{
button_press_time = 0;
button_status = BUTTON_NO_PRESS; // 按钮未按下
}
if(button_press_time >= BUTTON_LONG_PRESS_TIME)
{
button_status = BUTTON_LONG_PRESS; // 设置按钮状态为长按
}
else if(button_press_time >= BUTTON_SHORT_PRESS_TIME && button_status != BUTTON_SHORT_PRESS_HANDLED)
{
button_status = BUTTON_SHORT_PRESS; // 设置按钮状态为短按
}
}
button_status_enum button_get_status()
{
if(button_status == BUTTON_SHORT_PRESS)
{
button_status = BUTTON_SHORT_PRESS_HANDLED; // 短按已处理
return BUTTON_SHORT_PRESS;
}
else
{
return button_status;
}
}
void button_led_set(button_led_enum led)
{
gpio_set_level(BUTTON_LED_R, led == BUTTON_LED_R);
gpio_set_level(BUTTON_LED_G, led == BUTTON_LED_G);
gpio_set_level(BUTTON_LED_O, led == BUTTON_LED_O);
}

200
Source/clock_init.c Normal file
View File

@@ -0,0 +1,200 @@
#include "clock_init.h"
#include "delay.h"
#include "uart.h"
//22.11MHz的IRC参数寄存器 0xFB
//24MHz的IRC参数寄存器 0xFB
#define IRC_22M (*((uint8 idata*)0xFA))
#define IRC_24M (*((uint8 idata*)0xFB))
//内核频率
int32 sys_clk = FOSC;
//-------------------------------------------------------------------------------------------------------------------
// @brief STC32G设置系统频率
// @param NULL 空值
// @return void 系统频率
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
uint32 set_clk(void)
{
P_SW2 |= 0x80;
if(sys_clk == 22118400)
{
//选择 22.1184MHz
CLKDIV = 0x04;
IRTRIM = T22M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
else if(sys_clk == 24000000)
{
//选择 24MHz
CLKDIV = 0x04;
IRTRIM = T24M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
else if(sys_clk == 27000000)
{
//选择 27MHz
CLKDIV = 0x04;
IRTRIM = T27M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
else if(sys_clk == 30000000)
{
//选择 30MHz
CLKDIV = 0x04;
IRTRIM = T30M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
else if(sys_clk == 33177600)
{
//选择 33.1776MHz
CLKDIV = 0x04;
IRTRIM = T33M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
else if(sys_clk == 35000000)
{
//选择 35MHz
CLKDIV = 0x04;
IRTRIM = T35M_ADDR;
VRTRIM = VRT44M_ADDR;
IRCBAND = 0x03;
CLKDIV = 0x00;
}
else
{
sys_clk = 30000000;
//选择 30MHz
CLKDIV = 0x04;
IRTRIM = T30M_ADDR;
VRTRIM = VRT27M_ADDR;
IRCBAND = 0x02;
CLKDIV = 0x00;
}
return sys_clk;
}
void board_init(void)
{
EAXFR = 1; // 使能访问XFR
CKCON = 0x00; // 设置外部数据总线为最快
WTST = 0; // 设置程序代码等待参数赋值为0可将CPU执行程序的速度设置为最快
SET_P54_RESRT; // 使P54为复位引脚
P_SW2 = 0x80; // 开启特殊地址访问
#if (1 == EXTERNAL_CRYSTA_ENABLE)
XOSCCR = 0xc0; //启动外部晶振
while (!(XOSCCR & 1)); //等待时钟稳定
CLKDIV = 0x00; //时钟不分频
CLKSEL = 0x01; //选择外部晶振
#else
//自动设置系统频率
#if (0 == FOSC)
sys_clk = set_clk();
#else
sys_clk = FOSC;
#endif
#endif
delay_init(); //延时函数初始化
WTST = 0;
P_SW2 |= 0x80;
CLKDIV = 0; //24MHz主频分频设置
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
P6M0 = 0x00;
P6M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
ADCCFG = 0;
AUXR = 0;
SCON = 0;
S2CON = 0;
S3CON = 0;
S4CON = 0;
P_SW1 = 0;
IE2 = 0;
TMOD = 0;
P_SW2 |= 0x80;
#if (1 == USE_USB_CDC)
P3M0 &= ~0x03;
P3M1 |= 0x03;
IRC48MCR = 0x80;
while (!(IRC48MCR & 0x01));
USBCLK = 0x00;
USBCON = 0x90;
usb_init();
IE2 |= 0x80;
EA = 1;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
#else
uart_init(DEBUG_UART, DEBUG_UART_RX_PIN, DEBUG_UART_TX_PIN, DEBUG_UART_BAUD, DEBUG_UART_TIM);
#endif
EnableGlobalIRQ();
}
#if (1 == PRINTF_ENABLE)
#if (1==USE_USB_CDC)
#else
//重定义printf 数字 只能输出uint16
char putchar(char c)
{
uart_putchar(DEBUG_UART, c);//把自己实现的串口打印一字节数据的函数替换到这里
return c;
}
#endif
#endif
void DisableGlobalIRQ(void)
{
EA = 0;
}
void EnableGlobalIRQ(void)
{
EA = 1;
}

141
Source/command.c Normal file
View File

@@ -0,0 +1,141 @@
#include "command.h"
uint8 command_buffer[COMMAND_BUFFER_SIZE]; // 命令缓冲区
static uint8 command_buffer_index = 0; // 当前命令索引
static vuint8 is_busy_command = 0;
/************************************************************
* 名称 getIntFromStr()
* 功能 :从字符串中获取整数
* 输入 void
* 输出 int
* 说明 :从字符串中获取整数,自动移动指针,遇到特殊字符停止
************************************************************/
int16 getIntFromStr()
{
int16 result = 0;
int8 is_negative = 1; // 是否为负数
bit has_get = 0;
while(command_buffer[command_buffer_index])
{
if(command_buffer[command_buffer_index] == ' ' || command_buffer[command_buffer_index] == ';' || command_buffer[command_buffer_index] == '\r' || command_buffer[command_buffer_index] == '\n' || command_buffer[command_buffer_index] == '\0')
{
if(has_get)
{
break;
}
command_buffer_index++;
continue;
}
else if(command_buffer[command_buffer_index] == '-')
{
is_negative = -1;
}
else if(command_buffer[command_buffer_index] >= '0' && command_buffer[command_buffer_index] <= '9')
{
has_get = 1;
result = result*10 + command_buffer[command_buffer_index] - '0';
}
else if(command_buffer[command_buffer_index] == '.')
{
command_buffer_index++;
while(command_buffer[command_buffer_index] >= '0' && command_buffer[command_buffer_index] <= '9')command_buffer_index++;
}
else
{
result = 0;
break;
}
command_buffer_index++;
}
return result * is_negative; // 返回结果
}
/************************************************************
* 名称 startWith()
* 功能 :判断字符串是否以某个字符串开头
* 输入 uint8 *str,uint8 *cmd,uint8 offset
* 输出 uint8
* 说明 :判断字符串是否以某个字符串开头
************************************************************/
uint8 startWith(uint8 *str, uint8 *cmd,uint8 offset,uint8 *counter)
{
uint8 cou,k;
k = offset;
for(cou=0;*cmd;cou++)
{
if(*(str+cou+k) != *cmd)
{
(*counter) -= cou;
return 0;
}
cmd++;
(*counter) ++;
}
return 1;
}
/************************************************************
* 名称 parseCommand()
* 功能 :解析命令
* 输入 :无
* 输出 :无
* 说明 :解析命令
************************************************************/
void parseCommand()
{
uint8 cmd_state = 1; // 命令状态
if(!is_busy_command) return; // 如果没有忙状态,直接返回
command_buffer[command_buffer_index] = '\0';
command_buffer_index = 0;
if(startWith(command_buffer,"POW",0,&command_buffer_index))
{
// command_buffer_index += 2;
if(command_buffer[command_buffer_index] == ' ')
{
// int16 power_index = 1000;
// power_index = getIntFromStr();
// if(startWith(command_buffer," ON",command_buffer_index,&command_buffer_index))
// {
// }
// else if(startWith(command_buffer," OFF",command_buffer_index,&command_buffer_index))
// {
// }
// if(command_buffer[command_buffer_index] == ';')
// {
// cmd_state = 0; // 命令成功
// }
}
}
if(cmd_state)
{
printf("Error!\r\n");
}
else
{
printf("OK!\r\n");
}
command_buffer_index = 0;
is_busy_command = 0;
}
void command_uart_callback(uint8 dat)
{
if(is_busy_command) return;
command_buffer[command_buffer_index++] = dat;
if(command_buffer[command_buffer_index-1] == ';')
{
is_busy_command = 1; // 设置忙状态,防止中断嵌套
}
if(command_buffer_index >= COMMAND_BUFFER_SIZE)
{
command_buffer_index = 0; // 防止缓冲区溢出
}
}

51
Source/delay.c Normal file
View File

@@ -0,0 +1,51 @@
#include "delay.h"
static vuint16 delay_ms_a = 0;
static vuint16 delay_us_a = 0;
//-------------------------------------------------------------------------------------------------------------------
// @brief 软件延时函数初始化
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
void delay_init(void)
{
delay_ms_a = sys_clk / 6000;
delay_us_a = sys_clk / 7000000;
if(sys_clk <= 12000000) delay_us_a++;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 软件延时函数
// @param x 需要延时的时间ms
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
void delay_ms(uint16 ms)
{
uint16 i;
do {
i = delay_ms_a;
//i = sys_clk/6000;//参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
while(--i);
}while(--ms);
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 软件延时函数(这是一个不准确的延时)
// @param x 需要延时的时间us
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
void delay_us(uint32 us)
{
uint16 i;
do {
i = delay_us_a;
//i = sys_clk/6000;//参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
while(--i);
}while(--us);
}

38
Source/exti.c Normal file
View File

@@ -0,0 +1,38 @@
#include "exti.h"
//-------------------------------------------------------------------------------------------------------------------
// @brief 外部中断初始化
// @param NULL
// @return void
// Sample usage: exit_init(INT0_P32,BOTH) //初始化P32 作为外部中断引脚,双边沿触发。
//-------------------------------------------------------------------------------------------------------------------
void exit_init(INTN_enum int_n,INT_MODE_enum mode)
{
if(INT0_P32 == int_n)
{
IT0 = mode;
EX0 = 1; //使能INT0中断
}
if(INT1_P33 == int_n)
{
IT1 = mode;
EX1 = 1; //使能INT1中断
}
if(INT2_P36 == int_n)
{
INTCLKO |= 1<<4; //使能INT2中断
}
if(INT3_P37 == int_n)
{
INTCLKO |= 1<<5; //使能INT3中断
}
if(INT4_P30 == int_n)
{
INTCLKO |= 1<<6; //使能INT4中断
}
}

523
Source/fifo.c Normal file
View File

@@ -0,0 +1,523 @@
#include "fifo.h"
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 FIFO 头指针位移
// 参数说明 *fifo FIFO 对象指针
// 参数说明 offset 偏移量
// 返回参数 void
// 使用示例 fifo_head_offset(fifo, 1);
// 备注信息 本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
static void fifo_head_offset (fifo_struct *fifo, uint32 offset)
{
fifo->head += offset;
while(fifo->max <= fifo->head) // 如果范围超过则减缓冲区大小 直到小于最大缓冲区大小
{
fifo->head -= fifo->max;
}
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 FIFO 尾指针位移
// 参数说明 *fifo FIFO 对象指针
// 参数说明 offset 偏移量
// 返回参数 void
// 使用示例 fifo_end_offset(fifo, 1);
// 备注信息 本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
static void fifo_end_offset (fifo_struct *fifo, uint32 offset)
{
fifo->end += offset;
while(fifo->max <= fifo->end) // 如果范围超过则减缓冲区大小 直到小于最大缓冲区大小
{
fifo->end -= fifo->max;
}
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 FIFO 重置缓冲器
// 参数说明 *fifo FIFO 对象指针
// 返回参数 void
// 使用示例 fifo_clear(fifo);
// 备注信息 清空当前 FIFO 对象的内存
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_clear (fifo_struct *fifo)
{
//zf_assert(NULL != fifo);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
do
{
// if(FIFO_IDLE != fifo->execution) // 判断是否当前 FIFO 是否空闲
// {
// return_state = FIFO_RESET_UNDO; // 重置操作未完成
// break;
// }
fifo->execution |= FIFO_RESET; // 重置操作置位
fifo->head = 0; // 重置 FIFO 所有数值复位
fifo->end = 0; // 重置 FIFO 所有数值复位
fifo->reamin_size = fifo->max; // 重置 FIFO 所有数值复位
switch(fifo->type)
{
case FIFO_DATA_8BIT: memset(fifo->buffer, 0, (uint16)fifo->max); break;
case FIFO_DATA_16BIT: memset(fifo->buffer, 0, (uint16)fifo->max * 2); break;
case FIFO_DATA_32BIT: memset(fifo->buffer, 0, (uint16)fifo->max * 4); break;
}
fifo->execution = FIFO_IDLE; // 操作状态复位
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 FIFO 查询当前数据个数
// 参数说明 *fifo FIFO 对象指针
// 返回参数 uint32 已使用长度
// 使用示例 uint32 len = fifo_used(fifo);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
uint32 fifo_used (fifo_struct *fifo)
{
//zf_assert(fifo != NULL);
return (fifo->max - fifo->reamin_size); // 返回当前 FIFO 缓冲区中数据个数
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 向 FIFO 中写入数据
// 参数说明 *fifo FIFO 对象指针
// 参数说明 dat 数据
// 返回参数 fifo_state_enum 操作状态
// 使用示例 zf_log(fifo_write_element(&fifo, data) == FIFO_SUCCESS, "fifo_write_byte error");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_write_element (fifo_struct *fifo, uint32 dat)
{
//zf_assert(NULL != fifo);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
do
{
if((FIFO_RESET | FIFO_WRITE) & fifo->execution) // 不在写入与重置状态 避免写入竞争与指向错误
{
return_state = FIFO_WRITE_UNDO; // 写入操作未完成
break;
}
fifo->execution |= FIFO_WRITE; // 写入操作置位
if(1 <= fifo->reamin_size) // 剩余空间足够装下本次数据
{
switch(fifo->type)
{
case FIFO_DATA_8BIT: ((uint8 *)fifo->buffer)[fifo->head] = dat; break;
case FIFO_DATA_16BIT: ((uint16 *)fifo->buffer)[fifo->head] = dat; break;
case FIFO_DATA_32BIT: ((uint32 *)fifo->buffer)[fifo->head] = dat; break;
}
fifo_head_offset(fifo, 1); // 头指针偏移
fifo->reamin_size -= 1; // 缓冲区剩余长度减小
}
else
{
return_state = FIFO_SPACE_NO_ENOUGH; // 当前 FIFO 缓冲区满 不能再写入数据 返回空间不足
}
fifo->execution &= ~FIFO_WRITE; // 写入操作复位
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 向 FIFO 中写入数据
// 参数说明 *fifo FIFO 对象指针
// 参数说明 *dat 数据来源缓冲区指针
// 参数说明 length 需要写入的数据长度
// 返回参数 fifo_state_enum 操作状态
// 使用示例 zf_log(fifo_write_buffer(&fifo, data, 32) == FIFO_SUCCESS, "fifo_write_buffer error");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_write_buffer (fifo_struct *fifo, void *dat, uint32 length)
{
//zf_assert(NULL != fifo);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
uint32 temp_length = 0;
do
{
if(NULL == dat)
{
return_state = FIFO_BUFFER_NULL; // 用户缓冲区异常
break;
}
if((FIFO_RESET | FIFO_WRITE) & fifo->execution) // 不在写入与重置状态 避免写入竞争与指向错误
{
return_state = FIFO_WRITE_UNDO; // 写入操作未完成
break;
}
fifo->execution |= FIFO_WRITE; // 写入操作置位
if(length <= fifo->reamin_size) // 剩余空间足够装下本次数据
{
temp_length = fifo->max - fifo->head; // 计算头指针距离缓冲区尾还有多少空间
if(length > temp_length) // 距离缓冲区尾长度不足写入数据 环形缓冲区分段操作
{
switch(fifo->type)
{
case FIFO_DATA_8BIT:
{
memcpy(
&(((uint8 *)fifo->buffer)[fifo->head]),
dat, (uint16)temp_length); // 拷贝第一段数据
fifo_head_offset(fifo, temp_length); // 头指针偏移
memcpy(
&(((uint8 *)fifo->buffer)[fifo->head]),
&(((uint8 *)dat)[temp_length]),
(uint16)(length - temp_length)); // 拷贝第二段数据
fifo_head_offset(fifo, length - temp_length); // 头指针偏移
}break;
case FIFO_DATA_16BIT:
{
memcpy(
&(((uint16 *)fifo->buffer)[fifo->head]),
dat, temp_length * 2); // 拷贝第一段数据
fifo_head_offset(fifo, temp_length); // 头指针偏移
memcpy(
&(((uint16 *)fifo->buffer)[fifo->head]),
&(((uint16 *)dat)[temp_length]),
(length - temp_length) * 2); // 拷贝第二段数据
fifo_head_offset(fifo, length - temp_length); // 头指针偏移
}break;
case FIFO_DATA_32BIT:
{
memcpy(
&(((uint32 *)fifo->buffer)[fifo->head]),
dat, temp_length * 4); // 拷贝第一段数据
fifo_head_offset(fifo, temp_length); // 头指针偏移
memcpy(
&(((uint32 *)fifo->buffer)[fifo->head]),
&(((uint32 *)dat)[temp_length]),
(length - temp_length) * 4); // 拷贝第二段数据
fifo_head_offset(fifo, length - temp_length); // 头指针偏移
}break;
}
}
else
{
switch(fifo->type)
{
case FIFO_DATA_8BIT:
{
memcpy(
&(((uint8 *)fifo->buffer)[fifo->head]),
dat, (uint16)length); // 一次完整写入
fifo_head_offset(fifo, length); // 头指针偏移
}break;
case FIFO_DATA_16BIT:
{
memcpy(
&(((uint16 *)fifo->buffer)[fifo->head]),
dat, length * 2); // 一次完整写入
fifo_head_offset(fifo, length); // 头指针偏移
}break;
case FIFO_DATA_32BIT:
{
memcpy(
&(((uint32 *)fifo->buffer)[fifo->head]),
dat, length * 4); // 一次完整写入
fifo_head_offset(fifo, length); // 头指针偏移
}break;
}
}
fifo->reamin_size -= length; // 缓冲区剩余长度减小
}
else
{
return_state = FIFO_SPACE_NO_ENOUGH; // 当前 FIFO 缓冲区满 不能再写入数据 返回空间不足
}
fifo->execution &= ~FIFO_WRITE; // 写入操作复位
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 从 FIFO 读取数据
// 参数说明 *fifo FIFO 对象指针
// 参数说明 *dat 目标缓冲区指针
// 参数说明 flag 是否变更 FIFO 状态 可选择是否清空读取的数据
// 返回参数 fifo_state_enum 操作状态
// 使用示例 zf_log(fifo_read_element(&fifo, data, FIFO_READ_ONLY) == FIFO_SUCCESS, "fifo_read_byte error");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_element (fifo_struct *fifo, void *dat, fifo_operation_enum flag)
{
//zf_assert(NULL != fifo);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
do
{
if(NULL == dat)
{
return_state = FIFO_BUFFER_NULL; // 用户缓冲区异常
}
else
{
if((FIFO_RESET | FIFO_CLEAR) & fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
{
return_state = FIFO_READ_UNDO; // 读取操作未完成
break;
}
if(1 > fifo_used(fifo))
{
return_state = FIFO_DATA_NO_ENOUGH; // 缓冲区没有数据 返回数据长度不足
break; // 直接退出操作
}
fifo->execution |= FIFO_READ; // 读操作置位
switch(fifo->type)
{
case FIFO_DATA_8BIT: *((uint8 *)dat) = ((uint8 *)fifo->buffer)[fifo->end]; break;
case FIFO_DATA_16BIT: *((uint16 *)dat) = ((uint16 *)fifo->buffer)[fifo->end]; break;
case FIFO_DATA_32BIT: *((uint32 *)dat) = ((uint32 *)fifo->buffer)[fifo->end]; break;
}
fifo->execution &= ~FIFO_READ; // 读操作复位
}
if(FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
{
if((FIFO_RESET | FIFO_CLEAR | FIFO_READ) == fifo->execution) // 不在 重置 清空 读取 状态 避免异常
{
return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
break;
}
fifo->execution |= FIFO_CLEAR; // 清空作置位
fifo_end_offset(fifo, 1); // 移动 FIFO 头指针
fifo->reamin_size += 1; // 释放对应长度空间
fifo->execution &= ~FIFO_CLEAR; // 清空作复位
}
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 从 FIFO 读取数据
// 参数说明 *fifo FIFO 对象指针
// 参数说明 *dat 目标缓冲区指针
// 参数说明 *length 读取的数据长度 如果没有这么多数据这里会被修改
// 参数说明 flag 是否变更 FIFO 状态 可选择是否清空读取的数据
// 返回参数 fifo_state_enum 操作状态
// 使用示例 zf_log(fifo_read_buffer(&fifo, data, &length, FIFO_READ_ONLY) == FIFO_SUCCESS, "fifo_read_buffer error");
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_buffer (fifo_struct *fifo, void *dat, uint32 *length, fifo_operation_enum flag)
{
//zf_assert(NULL != fifo);
//zf_assert(NULL != length);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
uint32 temp_length = 0;
uint32 fifo_data_length = 0;
do
{
if(NULL == dat)
{
return_state = FIFO_BUFFER_NULL;
}
else
{
if((FIFO_RESET | FIFO_CLEAR) & fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
{
*length = fifo_data_length; // 纠正读取的长度
return_state = FIFO_READ_UNDO; // 读取操作未完成
break;
}
fifo_data_length = fifo_used(fifo); // 获取当前数据有多少
if(*length > fifo_data_length) // 判断长度是否足够
{
*length = fifo_data_length; // 纠正读取的长度
return_state = FIFO_DATA_NO_ENOUGH; // 标志数据不够
if(0 == fifo_data_length) // 如果没有数据 就直接退出
{
fifo->execution &= ~FIFO_READ; // 读操作复位
break;
}
}
fifo->execution |= FIFO_READ; // 读操作置位
temp_length = fifo->max - fifo->end; // 计算尾指针距离缓冲区尾还有多少空间
if(*length <= temp_length) // 足够一次性读取完毕
{
switch(fifo->type)
{
case FIFO_DATA_8BIT: memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->end]), (uint16)*length); break;
case FIFO_DATA_16BIT: memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->end]), (uint16)*length * 2); break;
case FIFO_DATA_32BIT: memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->end]), (uint16)*length * 4); break;
}
}
else
{
switch(fifo->type)
{
case FIFO_DATA_8BIT:
{
memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->end]), (uint16)temp_length);
memcpy(&(((uint8 *)dat)[temp_length]), fifo->buffer, (uint16)(*length - temp_length));
}break;
case FIFO_DATA_16BIT:
{
memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->end]), (uint16)(temp_length * 2));
memcpy(&(((uint16 *)dat)[temp_length]), fifo->buffer, (uint16)((*length - temp_length) * 2));
}break;
case FIFO_DATA_32BIT:
{
memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->end]), (uint16)(temp_length * 4));
memcpy(&(((uint32 *)dat)[temp_length]), fifo->buffer, (uint16)((*length - temp_length) * 4));
}break;
}
}
fifo->execution &= ~FIFO_READ; // 读操作复位
}
if(FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
{
if((FIFO_RESET | FIFO_CLEAR | FIFO_READ) == fifo->execution) // 不在 重置 清空 读取 状态 避免异常
{
return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
break;
}
fifo->execution |= FIFO_CLEAR; // 清空作置位
fifo_end_offset(fifo, *length); // 移动 FIFO 头指针
fifo->reamin_size += *length; // 释放对应长度空间
fifo->execution &= ~FIFO_CLEAR; // 清空作复位
}
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 从 FIFO 尾部读取指定长度 buffer
// 参数说明 *fifo FIFO 对象指针
// 参数说明 *dat 目标缓冲区指针
// 参数说明 *length 读取的数据长度 如果没有这么多数据这里会被修改
// 参数说明 flag 是否变更 FIFO 状态 可选择是否清空读取的数据
// 返回参数 fifo_state_enum 操作状态
// 使用示例 zf_log(fifo_read_tail_buffer(&fifo, data, &length, FIFO_READ_ONLY) == FIFO_SUCCESS, "fifo_read_buffer error");
// 备注信息 如果使用 FIFO_READ_AND_CLEAN 操作 将会丢弃所有数据并清空整个 FIFO
// 如果使用 FIFO_READ_AND_CLEAN 操作 将会丢弃所有数据并清空整个 FIFO
// 如果使用 FIFO_READ_AND_CLEAN 操作 将会丢弃所有数据并清空整个 FIFO
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_read_tail_buffer (fifo_struct *fifo, void *dat, uint32 *length, fifo_operation_enum flag)
{
//zf_assert(NULL != fifo);
//zf_assert(NULL != length);
fifo_state_enum return_state = FIFO_SUCCESS; // 操作结果初值
uint32 temp_length = 0;
uint32 fifo_data_length = 0;
do
{
if(NULL == dat)
{
return_state = FIFO_BUFFER_NULL;
}
else
{
if((FIFO_RESET | FIFO_CLEAR | FIFO_WRITE) & fifo->execution) // 判断是否当前 FIFO 是否在执行清空或重置操作
{
*length = fifo_data_length; // 纠正读取的长度
return_state = FIFO_READ_UNDO; // 读取操作未完成
break;
}
fifo_data_length = fifo_used(fifo); // 获取当前数据有多少
if(*length > fifo_data_length) // 判断长度是否足够
{
*length = fifo_data_length; // 纠正读取的长度
return_state = FIFO_DATA_NO_ENOUGH; // 标志数据不够
if(0 == fifo_data_length) // 如果没有数据 就直接退出
{
fifo->execution &= ~FIFO_READ; // 读操作复位
break;
}
}
fifo->execution |= FIFO_READ; // 读操作置位
if((fifo->head > fifo->end) || (fifo->head >= *length))
{
switch(fifo->type)
{
case FIFO_DATA_8BIT: memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->head - *length]), (uint16)*length); break;
case FIFO_DATA_16BIT: memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->head - *length]), (uint16)(*length * 2));break;
case FIFO_DATA_32BIT: memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->head - *length]), (uint16)(*length * 4));break;
}
}
else
{
temp_length = *length - fifo->head; // 计算尾指针距离缓冲区尾还有多少空间
switch(fifo->type)
{
case FIFO_DATA_8BIT:
{
memcpy(dat, &(((uint8 *)fifo->buffer)[fifo->max - temp_length]), (uint16)temp_length);
memcpy(&(((uint8 *)dat)[temp_length]), &(((uint8 *)fifo->buffer)[fifo->head - *length]), (uint16)(*length - temp_length));
}break;
case FIFO_DATA_16BIT:
{
memcpy(dat, &(((uint16 *)fifo->buffer)[fifo->max - temp_length]), temp_length * 2);
memcpy(&(((uint16 *)dat)[temp_length]), &(((uint16 *)fifo->buffer)[fifo->head - *length]), (uint16)((*length - temp_length) * 2));
}break;
case FIFO_DATA_32BIT:
{
memcpy(dat, &(((uint32 *)fifo->buffer)[fifo->max - temp_length]), temp_length * 4);
memcpy(&(((uint32 *)dat)[temp_length]), &(((uint32 *)fifo->buffer)[fifo->head - *length]), (uint16)((*length - temp_length) * 4));
}break;
}
}
fifo->execution &= ~FIFO_READ; // 读操作复位
}
if(FIFO_READ_AND_CLEAN == flag) // 如果选择读取并更改 FIFO 状态
{
if((FIFO_RESET | FIFO_CLEAR | FIFO_READ) == fifo->execution) // 不在 重置 清空 读取 状态 避免异常
{
return_state = FIFO_CLEAR_UNDO; // 清空操作未完成
break;
}
fifo_clear(fifo);
}
}while(0);
return return_state;
}
//-------------------------------------------------------------------------------------------------------------------
// 函数简介 FIFO 初始化 挂载对应缓冲区
// 参数说明 *fifo FIFO 对象指针
// 参数说明 type FIFO 数据位数
// 参数说明 *buffer_addr 要挂载的缓冲区
// 参数说明 size 缓冲区大小
// 返回参数 fifo_state_enum 操作状态
// 使用示例 fifo_init(&user_fifo, user_buffer, 64);
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
fifo_state_enum fifo_init (fifo_struct *fifo, fifo_data_type_enum type, void *buffer_addr, uint32 len)
{
//zf_assert(NULL != fifo);
fifo_state_enum return_state = FIFO_SUCCESS;
do
{
fifo->buffer = buffer_addr;
fifo->execution = FIFO_IDLE;
fifo->type = type;
fifo->head = 0;
fifo->end = 0;
fifo->reamin_size = len;
fifo->max = len;
}while(0);
return return_state;
}

313
Source/gpio.c Normal file
View File

@@ -0,0 +1,313 @@
#include "gpio.h"
#define PxPU_BASE_ADDR 0x7EFE10
void gpio_set_level(PIN_enum pin, uint8 level)
{
if(0x00 == (pin&0xF0)) //P0
{
if(level)
P0 |= (1<<(pin&0xF));
else
P0 &= ~(1<<(pin&0xF));
}
else if(0x10 == (pin&0xF0)) //P1
{
if(level)
P1 |= (1<<(pin&0xF));
else
P1 &= ~(1<<(pin&0xF));
}
else if(0x20 == (pin&0xF0)) //P2
{
if(level)
P2 |= (1<<(pin&0xF));
else
P2 &= ~(1<<(pin&0xF));
}
else if(0x30 == (pin&0xF0)) //P3
{
if(level)
P3 |= (1<<(pin&0xF));
else
P3 &= ~(1<<(pin&0xF));
}
else if(0x40 == (pin&0xF0)) //P4
{
if(level)
P4 |= (1<<(pin&0xF));
else
P4 &= ~(1<<(pin&0xF));
}
else if(0x50 == (pin&0xF0)) //P5
{
if(level)
P5 |= (1<<(pin&0xF));
else
P5 &= ~(1<<(pin&0xF));
}
else if(0x60 == (pin&0xF0)) //P6
{
if(level)
P6 |= (1<<(pin&0xF));
else
P6 &= ~(1<<(pin&0xF));
}
else if(0x70 == (pin&0xF0)) //P7
{
if(level)
P7 |= (1<<(pin&0xF));
else
P7 &= ~(1<<(pin&0xF));
}
}
uint8 gpio_get_level(PIN_enum pin)
{
uint8 level;
if(0x00 == (pin&0xF0)) //P0
{
level = (P0 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x10 == (pin&0xF0)) //P1
{
level = (P1 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x20 == (pin&0xF0)) //P2
{
level = (P2 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x30 == (pin&0xF0)) //P3
{
level = (P3 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x40 == (pin&0xF0)) //P4
{
level = (P4 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x50 == (pin&0xF0)) //P5
{
level = (P5 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x60 == (pin&0xF0)) //P6
{
level = (P6 & (1<<(pin&0xF))) ? 1 : 0;
}
else if(0x70 == (pin&0xF0)) //P7
{
level = (P7 & (1<<(pin&0xF))) ? 1 : 0;
}
return level;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief GPIO设置引脚上拉电阻设置
// @param pin 选择引脚P0_0-P7_7
// @param pull 设置上下拉电阻 NOPULL:不设置 PULLUP:上拉
// @return void
// Sample usage: gpio_pull_set(P0_0,NOPULL); // 设置P0.0引脚没有上下拉电阻
//-------------------------------------------------------------------------------------------------------------------
void gpio_pull_set(PIN_enum pin, PULL_enum pull)
{
if(PULLUP == pull)
{
(*(unsigned char volatile far *)(PxPU_BASE_ADDR + (pin >> 4))) |= (1<<(pin&0x0F));
}
else if(NOPULL == pull)
{
(*(unsigned char volatile far *)(PxPU_BASE_ADDR + (pin >> 4))) &= ~(1<<(pin&0x0F));
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief GPIO设置引脚模式
// @param pin 选择引脚P0_0-P5_4
// @param mode 引脚模式 GPIO:准双向口, GPO_PP:推挽输出, GPI_IMPEDANCE:高阻输入, GPI_OD:开漏输出
// @return void
// Sample usage: gpio_mode(P0_0,GPIO); // 设置P0.0设置为双向IO
//-------------------------------------------------------------------------------------------------------------------
void gpio_mode(PIN_enum pin, GPIOMODE_enum mode)
{
if(GPIO == mode)
{
if(0x00 == (pin&0xF0)) //P0
{
P0M1 &= ~(1<<(pin&0xF));
P0M0 &= ~(1<<(pin&0xF));
}
if(0x10 == (pin&0xF0)) //P1
{
P1M1 &= ~(1<<(pin&0xF));
P1M0 &= ~(1<<(pin&0xF));
}
if(0x20 == (pin&0xF0)) //P2
{
P2M1 &= ~(1<<(pin&0xF));
P2M0 &= ~(1<<(pin&0xF));
}
if(0x30 == (pin&0xF0)) //P3
{
P3M1 &= ~(1<<(pin&0xF));
P3M0 &= ~(1<<(pin&0xF));
}
if(0x40 == (pin&0xF0)) //P4
{
P4M1 &= ~(1<<(pin&0xF));
P4M0 &= ~(1<<(pin&0xF));
}
if(0x50 == (pin&0xF0)) //P5
{
P5M1 &= ~(1<<(pin&0xF));
P5M0 &= ~(1<<(pin&0xF));
}
if(0x60 == (pin&0xF0)) //P5
{
P6M1 &= ~(1<<(pin&0xF));
P6M0 &= ~(1<<(pin&0xF));
}
if(0x70 == (pin&0xF0)) //P5
{
P7M1 &= ~(1<<(pin&0xF));
P7M0 &= ~(1<<(pin&0xF));
}
}
else if(GPO_PP == mode)
{
if(0x00 == (pin&0xF0)) //P0
{
P0M1 &= ~(1<<(pin&0xF));
P0M0 |= (1<<(pin&0xF));
}
if(0x10 == (pin&0xF0)) //P1
{
P1M1 &= ~(1<<(pin&0xF));
P1M0 |= (1<<(pin&0xF));
}
if(0x20 == (pin&0xF0)) //P2
{
P2M1 &= ~(1<<(pin&0xF));
P2M0 |= (1<<(pin&0xF));
}
if(0x30 == (pin&0xF0)) //P3
{
P3M1 &= ~(1<<(pin&0xF));
P3M0 |= (1<<(pin&0xF));
}
if(0x40 == (pin&0xF0)) //P4
{
P4M1 &= ~(1<<(pin&0xF));
P4M0 |= (1<<(pin&0xF));
}
if(0x50 == (pin&0xF0)) //P5
{
P5M1 &= ~(1<<(pin&0xF));
P5M0 |= (1<<(pin&0xF));
}
if(0x60 == (pin&0xF0)) //P4
{
P6M1 &= ~(1<<(pin&0xF));
P6M0 |= (1<<(pin&0xF));
}
if(0x70 == (pin&0xF0)) //P5
{
P7M1 &= ~(1<<(pin&0xF));
P7M0 |= (1<<(pin&0xF));
}
}
else if(GPI_IMPEDANCE == mode)
{
if(0x00 == (pin&0xF0)) //P0
{
P0M1 |= (1<<(pin&0xF));
P0M0 &= ~(1<<(pin&0xF));
}
if(0x10 == (pin&0xF0)) //P1
{
P1M1 |= (1<<(pin&0xF));
P1M0 &= ~(1<<(pin&0xF));
}
if(0x20 == (pin&0xF0)) //P2
{
P2M1 |= (1<<(pin&0xF));
P2M0 &= ~(1<<(pin&0xF));
}
if(0x30 == (pin&0xF0)) //P3
{
P3M1 |= (1<<(pin&0xF));
P3M0 &= ~(1<<(pin&0xF));
}
if(0x40 == (pin&0xF0)) //P4
{
P4M1 |= (1<<(pin&0xF));
P4M0 &= ~(1<<(pin&0xF));
}
if(0x50 == (pin&0xF0)) //P5
{
P5M1 |= (1<<(pin&0xF));
P5M0 &= ~(1<<(pin&0xF));
}
if(0x60 == (pin&0xF0)) //P5
{
P6M1 |= (1<<(pin&0xF));
P6M0 &= ~(1<<(pin&0xF));
}
if(0x70 == (pin&0xF0)) //P5
{
P7M1 |= (1<<(pin&0xF));
P7M0 &= ~(1<<(pin&0xF));
}
}
else if(GPI_OD == mode)
{
if(0x00 == (pin&0xF0)) //P0
{
P0M1 |= (1<<(pin&0xF));
P0M0 |= (1<<(pin&0xF));
}
if(0x10 == (pin&0xF0)) //P1
{
P1M1 |= (1<<(pin&0xF));
P1M0 |= (1<<(pin&0xF));
}
if(0x20 == (pin&0xF0)) //P2
{
P2M1 |= (1<<(pin&0xF));
P2M0 |= (1<<(pin&0xF));
}
if(0x30 == (pin&0xF0)) //P3
{
P3M1 |= (1<<(pin&0xF));
P3M0 |= (1<<(pin&0xF));
}
if(0x40 == (pin&0xF0)) //P4
{
P4M1 |= (1<<(pin&0xF));
P4M0 |= (1<<(pin&0xF));
}
if(0x50 == (pin&0xF0)) //P5
{
P5M1 |= (1<<(pin&0xF));
P5M0 |= (1<<(pin&0xF));
}
if(0x60 == (pin&0xF0)) //P5
{
P6M1 |= (1<<(pin&0xF));
P6M0 |= (1<<(pin&0xF));
}
if(0x70 == (pin&0xF0)) //P5
{
P7M1 |= (1<<(pin&0xF));
P7M0 |= (1<<(pin&0xF));
}
}
}

91
Source/hx711.c Normal file
View File

@@ -0,0 +1,91 @@
#include "hx711.h"
#include "gpio.h"
uint32 hx711_last_read_value[10];
void hx711_init()
{
gpio_mode(HX711_DT_PIN, GPIO); // 设置DT引脚为推挽输出
gpio_mode(HX711_SCK_PIN, GPIO); // 设置SCK引脚为推挽输出
gpio_set_level(HX711_SCK_PIN, 0); // 初始化SCK为低电平
gpio_set_level(HX711_DT_PIN, 1); // 初始化DT为高电平
}
uint32 hx711_read_set(HX711_ch_enum next_ch,uint8 avg_times)
{
uint32 result = 0;
uint8 i;
if(avg_times > 10) /* 限制平均次数最大值为10 */
{
avg_times = 10;
}
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平开始读数据 */
gpio_set_level(HX711_DT_PIN, 1); /* 确保DT高电平等待HX711准备好数据 */
while(gpio_get_level(HX711_DT_PIN) == 1); /* 等待HX711准备好数据 */
for(i = 0; i < 24; i++)
{
gpio_set_level(HX711_SCK_PIN, 1); /* SCK高电平 */
result <<= 1; /* 左移一位 */
if(gpio_get_level(HX711_DT_PIN) == 1)
{
result |= 0x01; /* 如果DT为高电平设置最低位为1 */
}
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平 */
}
for(i = 0; i < next_ch; i++)
{
gpio_set_level(HX711_SCK_PIN, 1); /* SCK高电平 */
_nop_();
_nop_();
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平 */
}
for(i = 0; i < 9; i++)
{
hx711_last_read_value[i] = hx711_last_read_value[i + 1]; /* 将之前的读取值向前移动 */
}
hx711_last_read_value[9] = result; /* 将当前读取的值存入最后一个位置 */
result = 0;
for(i = 0; i < avg_times; i++)
{
result += hx711_last_read_value[i]/avg_times; /* 累加读取的值 */
}
return result; /* 返回读取到的数据 */
}
uint8 hx711_single_read_non_blocking(HX711_ch_enum next_ch)
{
uint32 result = 0;
uint8 i;
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平开始读数据 */
gpio_set_level(HX711_DT_PIN, 1); /* 确保DT高电平等待HX711准备好数据 */
if(gpio_get_level(HX711_DT_PIN) == 1)
{
return 0; /* 如果DT为高电平表示HX711未准备好数据 */
}
for(i = 0; i < 24; i++)
{
gpio_set_level(HX711_SCK_PIN, 1); /* SCK高电平 */
result <<= 1; /* 左移一位 */
if(gpio_get_level(HX711_DT_PIN) == 1)
{
result |= 0x01; /* 如果DT为高电平设置最低位为1 */
}
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平 */
}
for(i = 0; i < next_ch; i++)
{
gpio_set_level(HX711_SCK_PIN, 1); /* SCK高电平 */
_nop_();
_nop_();
gpio_set_level(HX711_SCK_PIN, 0); /* SCK低电平 */
}
for(i = 0; i < 9; i++)
{
hx711_last_read_value[i] = hx711_last_read_value[i + 1]; /* 将之前的读取值向前移动 */
}
hx711_last_read_value[9] = result; /* 将当前读取的值存入最后一个位置 */
return 1;
}

349
Source/iic.c Normal file
View File

@@ -0,0 +1,349 @@
#include "iic.h"
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
void iic_delay_us(uint16 x) //33.1776Mhz
{
uint8 i;
while(x--)
{
i = 9;
while (--i);
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 wait(void)
{
uint16 count = 0;
uint8 ret = IIC_SEND_OK;
while (!(I2CMSST & 0x40))
{
iic_delay_us(1);
if(count++ >= 30)//等待超过30us则退出等待。
{
ret = IIC_SEND_FAIL;
break;
}
}
I2CMSST &= ~0x40;
return ret;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 start(void)
{
uint8 ret;
I2CMSCR = 0x01; //发送start命令
ret = wait();
return ret;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 send_data(char dat)
{
uint8 ret;
I2CTXD = dat; //写数据到数据缓冲区
I2CMSCR = 0x02; //发送SEND命令
ret = wait();
return ret;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 recv_ack(void)
{
uint8 ret;
I2CMSCR = 0x03; //发送读ACK命令
ret = wait();
return ret;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
char recv_data(void) //接收数据
{
I2CMSCR = 0x04; //发送RECV命令
wait();
return I2CRXD;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 send_ack(void)
{
uint8 ret;
I2CMSST = 0x00; //设置ACK信号
I2CMSCR = 0x05; //发送ACK命令
ret = wait();
return ret;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
void send_nak(void)
{
I2CMSST = 0x01; //设置NAK信号
I2CMSCR = 0x05; //发送ACK命令
wait();
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 内部使用用户无需关心
// @param NULL
// @return void
// Sample usage: 无需用户调用用户请使用h文件中的宏定义
//-------------------------------------------------------------------------------------------------------------------
uint8 stop(void)
{
uint8 ret;
I2CMSCR = 0x06; //发送stop命令
ret = wait();
return ret;
}
//#define UNUSED(expr1, expr2) do { if(scl_pin == sda_pin); } while (0)
//-------------------------------------------------------------------------------------------------------------------
// @brief 硬件IIC初始化
// @param iic_n 选择IIC模块
// @param wait_time I2C总线速度等待时钟数控制: 速度设置为等待wait_time*2+1个时钟
// @return void
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void iic_init(IICN_enum iic_n, uint8 wait_time)
{
//UNUSED(scl_pin);
//__attribute__ ((unused))(sda_pin);
//UNUSED(scl_pin, sda_pin);
P_SW2 &= ~(0x03<<4);
P_SW2 |= 1<<7; //将EAXFR寄存器置1这样才能使用特殊功能寄存器为扩展SFR访问逻辑地址位于 XDATA 区域
switch(iic_n)
{
case IIC_1:
P_SW2 |= (0x00<<4); //SCL:P1.5 SDA:P1.4
break;
case IIC_2:
P_SW2 |= (0x01<<4); //SCL:P2.5 SDA:P2.4
break;
case IIC_3:
P_SW2 |= (0x02<<4); //SCL:P7.7 SDA:P7.6
break;
case IIC_4:
P_SW2 |= (0x03<<4); //SCL:P3.2 SDA:P3.3
break;
}
I2CCFG |= 1<<6; //主机模式
I2CCFG |= 1<<7; //使能IIC
I2CCFG |= wait_time&0x3F;//速度设置为等待wait_time*2+1个时钟
I2CMSST = 0x00; //主机状态寄存器
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 写入一个字节数据到I2C设备指定寄存器地址
// @param iic_n IIC模块(IIC_1,IIC_2,IIC_3,IIC_0)
// @param slaveid 从机地址(7位地址)
// @param reg 从机寄存器地址
// @param dat 需要发送的数据
// @return 返回的状态值 0成功 1失败
// @since v2.0
// Sample usage: iic_write_reg(0x2D, 0x50,2); //写入数据2到0x50地址从机地址为0x2D
//-------------------------------------------------------------------------------------------------------------------
uint8 iic_write_reg(uint8 dev_add, uint8 reg, uint8 dat)
{
if(start() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data(reg) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data(dat) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(stop() != IIC_SEND_OK)
return IIC_SEND_FAIL;
return IIC_SEND_OK;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 读取I2C设备指定地址寄存器的数据
// @param iic_n I2C通道号及引脚
// @param dev_add 从机地址(7位地址)
// @param reg 从机寄存器地址
// @param dat 数据地址
// @return 读取的寄存器值
// @since v1.0
// Sample usage: uint8 value = iic_read_reg(i2c0, 0x2D, 0x50);//读取0x50地址的数据从机地址为0x2D
//-------------------------------------------------------------------------------------------------------------------
uint8 iic_read_reg(uint8 dev_add, uint8 reg, uint8 *dat)
{
if(start() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data(reg) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
// if(start() != IIC_SEND_OK)
// return IIC_SEND_FAIL;
if(send_data((dev_add<<1) | 0x01) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
*dat = recv_data(); //读取数据
if(send_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(stop() != IIC_SEND_OK)
return IIC_SEND_FAIL;
return IIC_SEND_OK;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 读取I2C设备指定地址寄存器的数据
// @param iic_n I2C通道号及引脚
// @param dev_add 从机地址(7位地址)
// @param reg 从机寄存器地址
// @param dat 读取的数据存储的地址
// @param num 读取字节数
// @return void
// @since v1.0
// Sample usage: uint8 value = i2c_read_reg(i2c0, 0x2D, 0x50, 10, buf);//读取0x50地址的数据从机地址为0x2D开始的10个字节
//-------------------------------------------------------------------------------------------------------------------
uint8 iic_read_reg_bytes(uint8 dev_add, uint8 reg
, uint8 *dat, uint8 num)
{
if(start() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data((dev_add<<1) | 0x00) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data(reg) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(send_data((dev_add<<1) | 0x01) != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(recv_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
while(--num)
{
*dat = recv_data(); //读取数据
if(send_ack() != IIC_SEND_OK)
{
return IIC_SEND_FAIL;
}
dat++;
}
*dat = recv_data();
if(send_ack() != IIC_SEND_OK)
return IIC_SEND_FAIL;
if(stop() != IIC_SEND_OK)
return IIC_SEND_FAIL;
return IIC_SEND_OK;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 硬件IIC引脚切换函数
// @param iic_n I2C通道号及引脚
// @param scl_pin 选择SCL引脚
// @param sda_pin 选择SDA引脚
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void iic_change_pin(IICN_enum iic_n)
{
P_SW2 |= 1<<7; //将EAXFR寄存器置1这样才能使用特殊功能寄存器为扩展SFR访问逻辑地址位于 XDATA 区域
P_SW2 &= ~(0x03<<4); //清除引脚切换位
switch(iic_n)
{
case IIC_1:
P_SW2 |= (0x00<<4); //SCL:P1.5 SDA:P1.4
break;
case IIC_2:
P_SW2 |= (0x01<<4); //SCL:P2.5 SDA:P2.4
break;
case IIC_3:
P_SW2 |= (0x02<<4); //SCL:P7.7 SDA:P7.6
break;
case IIC_4:
P_SW2 |= (0x03<<4); //SCL:P3.2 SDA:P3.3
break;
}
P_SW2 &= ~(1<<7);
}

134
Source/iic_soft.c Normal file
View File

@@ -0,0 +1,134 @@
#include "iic_soft.h"
void soft_iic_delay(uint16 delay_time)
{
uint16 i;
// 简单的延时函数,可以根据实际需要调整
for (i = 0; i < delay_time; i++)
{
_nop_(); // 空操作,延时
}
}
void soft_iic_init(IIC_Soft_Config *config)
{
// 设置SCL和SDA引脚为推挽输出模式
gpio_mode(config->scl_pin, GPIO);
gpio_mode(config->sda_pin, GPIO);
// 初始化SCL和SDA引脚为高电平
gpio_set_level(config->scl_pin, 1);
gpio_set_level(config->sda_pin, 1);
}
void soft_iic_start(IIC_Soft_Config *config)
{
gpio_set_level(config->sda_pin, 0); // SDA拉低
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 0); // SCL拉低
soft_iic_delay(config->wait_time); // 等待一段时间
}
void soft_iic_stop(IIC_Soft_Config *config)
{
gpio_set_level(config->sda_pin, 0); // SDA拉低
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 1); // SCL拉高
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->sda_pin, 1); // SDA拉高
soft_iic_delay(config->wait_time); // 等待一段时间
}
uint8 soft_iic_read(IIC_Soft_Config *config)
{
uint8 dat = 0,i;
gpio_set_level(config->sda_pin, 1); // 设置SDA为输入模式
for (i = 0; i < 8; i++)
{
gpio_set_level(config->scl_pin, 1); // SCL拉高
soft_iic_delay(config->wait_time); // 等待一段时间
if (gpio_get_level(config->sda_pin)) // 读取SDA的状态
{
dat |= (1 << (7 - i)); // 将读取的位存入dat
}
gpio_set_level(config->scl_pin, 0); // SCL拉低
soft_iic_delay(config->wait_time); // 等待一段时间
}
return dat;
}
void soft_iic_write(IIC_Soft_Config *config, uint8 dat)
{
uint8 i;
gpio_set_level(config->sda_pin, 0); // 设置SDA为输出模式
for (i = 0; i < 8; i++)
{
soft_iic_delay(config->wait_time); // 等待一段时间
if (dat & (1 << (7 - i))) // 检查当前位
{
gpio_set_level(config->sda_pin, 1); // 写入1
}
else
{
gpio_set_level(config->sda_pin, 0); // 写入0
}
gpio_set_level(config->scl_pin, 1); // SCL拉高
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 0); // SCL拉低
}
soft_iic_delay(config->wait_time); // 等待一段时间
}
uint8 soft_iic_ack(IIC_Soft_Config *config)
{
gpio_set_level(config->sda_pin, 0); // 发送ACK
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 1); // SCL拉高
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 0); // SCL拉低
soft_iic_delay(config->wait_time); // 等待一段时间
return 0; // 返回ACK成功
}
void soft_iic_nack(IIC_Soft_Config *config)
{
gpio_set_level(config->sda_pin, 1); // 发送NACK
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 1); // SCL拉高
soft_iic_delay(config->wait_time); // 等待一段时间
gpio_set_level(config->scl_pin, 0); // SCL拉低
soft_iic_delay(config->wait_time); // 等待一段时间
}
void soft_iic_write_reg(IIC_Soft_Config *config, uint8 dev_addr, uint8 reg, uint8 dat)
{
soft_iic_start(config); // 发送起始信号
soft_iic_write(config, (dev_addr << 1) | 0); // 发送设备地址和写命令
soft_iic_ack(config); // 等待ACK
soft_iic_write(config, reg); // 发送寄存器地址
soft_iic_ack(config); // 等待ACK
soft_iic_write(config, dat); // 发送数据
soft_iic_ack(config); // 等待ACK
soft_iic_stop(config); // 发送停止信号
}
uint8 soft_iic_read_reg(IIC_Soft_Config *config, uint8 dev_addr, uint8 reg, uint8 *dat)
{
soft_iic_start(config); // 发送起始信号
soft_iic_write(config, (dev_addr << 1) | 0); // 发送设备地址和写命令
soft_iic_ack(config); // 等待ACK
soft_iic_write(config, reg); // 发送寄存器地址
soft_iic_ack(config); // 等待ACK
soft_iic_start(config); // 重新发送起始信号
soft_iic_write(config, (dev_addr << 1) | 1); // 发送设备地址和读命令
soft_iic_ack(config); // 等待ACK
*dat = soft_iic_read(config); // 读取数据
soft_iic_nack(config); // 发送NACK
soft_iic_stop(config); // 发送停止信号
return *dat; // 返回读取的数据
}

172
Source/isr.c Normal file
View File

@@ -0,0 +1,172 @@
#include "isr.h"
#include "command.h"
//UART1中断
void UART1_Isr() interrupt 4
{
uint8 res;
static uint8 dwon_count;
if(UART1_GET_TX_FLAG)
{
UART1_CLEAR_TX_FLAG;
busy[1] = 0;
}
if(UART1_GET_RX_FLAG)
{
UART1_CLEAR_RX_FLAG;
res = SBUF;
//程序自动下载
if(res == 0x7F)
{
if(dwon_count++ > 20)
{
IAP_CONTR = 0x60;
}
}
else
{
dwon_count = 0;
}
command_uart_callback(res);
}
}
//UART2中断
void UART2_Isr() interrupt 8
{
if(UART2_GET_TX_FLAG)
{
UART2_CLEAR_TX_FLAG;
busy[2] = 0;
}
if(UART2_GET_RX_FLAG)
{
UART2_CLEAR_RX_FLAG;
//接收数据寄存器为S2BUF
}
}
//UART3中断
void UART3_Isr() interrupt 17
{
if(UART3_GET_TX_FLAG)
{
UART3_CLEAR_TX_FLAG;
busy[3] = 0;
}
if(UART3_GET_RX_FLAG)
{
UART3_CLEAR_RX_FLAG;
//接收数据寄存器为S3BUF
}
}
//UART4中断
void UART4_Isr() interrupt 18
{
if(UART4_GET_TX_FLAG)
{
UART4_CLEAR_TX_FLAG;
busy[4] = 0;
}
if(UART4_GET_RX_FLAG)
{
UART4_CLEAR_RX_FLAG;
//接收数据寄存器为S4BUF;
}
}
#define LED P52
void INT0_Isr() interrupt 0
{
}
void INT1_Isr() interrupt 2
{
}
void INT2_Isr() interrupt 10
{
INT2_CLEAR_FLAG; //清除中断标志
}
void INT3_Isr() interrupt 11
{
INT3_CLEAR_FLAG; //清除中断标志
}
void INT4_Isr() interrupt 16
{
INT4_CLEAR_FLAG; //清除中断标志
}
void TM0_Isr() interrupt 1
{
}
void TM1_Isr() interrupt 3
{
}
void TM2_Isr() interrupt 12
{
TIM2_CLEAR_FLAG; //清除中断标志
}
void TM3_Isr() interrupt 19
{
TIM3_CLEAR_FLAG; //清除中断标志
}
void TM4_Isr() interrupt 20
{
TIM4_CLEAR_FLAG; //清除中断标志
}
// void change_LED();
void P0_ISR() interrupt P0INT_VECTOR
{
if(P0INTF & 0x10) //P0.4
{
P0INTF &= ~0x10;
}
if(P0INTF & 0x20) //P0.5
{
P0INTF &= ~0x20;
}
}
//void INT0_Isr() interrupt 0;
//void TM0_Isr() interrupt 1;
//void INT1_Isr() interrupt 2;
//void TM1_Isr() interrupt 3;
//void UART1_Isr() interrupt 4;
//void ADC_Isr() interrupt 5;
//void LVD_Isr() interrupt 6;
//void PCA_Isr() interrupt 7;
//void UART2_Isr() interrupt 8;
//void SPI_Isr() interrupt 9;
//void INT2_Isr() interrupt 10;
//void INT3_Isr() interrupt 11;
//void TM2_Isr() interrupt 12;
//void INT4_Isr() interrupt 16;
//void UART3_Isr() interrupt 17;
//void UART4_Isr() interrupt 18;
//void TM3_Isr() interrupt 19;
//void TM4_Isr() interrupt 20;
//void CMP_Isr() interrupt 21;
//void I2C_Isr() interrupt 24;
//void USB_Isr() interrupt 25;
//void PWM1_Isr() interrupt 26;
//void PWM2_Isr() interrupt 27;

18
Source/main.c Normal file
View File

@@ -0,0 +1,18 @@
#include "common.h"
#include "delay.h"
void main()
{
board_init(); // 初始化板子
delay_ms(1000);
printf("System Init...\r\n");
while(1)
{
delay_ms(1000);
printf("System Running...\r\n");
}
}

437
Source/pwm.c Normal file
View File

@@ -0,0 +1,437 @@
#include "pwm.h"
#include "gpio.h"
//捕获比较模式寄存器
const uint32 PWM_CCMR_ADDR[] = {0x7efec8, 0x7efec9, 0x7efeca ,0x7efecb,
0x7efee8, 0x7efee9, 0x7efeea, 0x7efeeb};
//捕获比较使能寄存器
const uint32 PWM_CCER_ADDR[] = {0x7efecc, 0x7efecd,
0x7efeec ,0x7efeed};
//控制寄存器,高8位地址 低8位地址 + 1即可
const uint32 PWM_CCR_ADDR[] = {0x7efed5, 0x7efed7, 0x7efed9, 0x7efedb,
0x7efef5, 0x7efef7, 0x7efef9, 0x7efefb};
//控制寄存器,高8位地址 低8位地址 + 1即可
const uint32 PWM_ARR_ADDR[] = {0x7efed2,0x7efef2};
//-------------------------------------------------------------------------------------------------------------------
// @brief PWM_gpio初始化内部使用用户无需关心
// @param pwmch PWM通道号及引脚
// @return void
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void pwm_set_gpio(PWMCH_enum pwmch)
{
switch(pwmch)
{
case PWMA_CH1P_P10:
{
gpio_mode(P1_0,GPO_PP);
break;
}
case PWMA_CH1N_P11:
{
gpio_mode(P1_1,GPO_PP);
break;
}
case PWMA_CH1P_P20:
{
gpio_mode(P2_0,GPO_PP);
break;
}
case PWMA_CH1N_P21:
{
gpio_mode(P2_1,GPO_PP);
break;
}
case PWMA_CH1P_P60:
{
gpio_mode(P6_0,GPO_PP);
break;
}
case PWMA_CH1N_P61:
{
gpio_mode(P6_1,GPO_PP);
break;
}
case PWMA_CH2P_P12:
{
gpio_mode(P1_2,GPO_PP);
break;
}
case PWMA_CH2N_P13:
{
gpio_mode(P1_3,GPO_PP);
break;
}
case PWMA_CH2P_P22:
{
gpio_mode(P2_2,GPO_PP);
break;
}
case PWMA_CH2N_P23:
{
gpio_mode(P2_3,GPO_PP);
break;
}
case PWMA_CH2P_P62:
{
gpio_mode(P6_2,GPO_PP);
break;
}
case PWMA_CH2N_P63:
{
gpio_mode(P6_3,GPO_PP);
break;
}
case PWMA_CH3P_P14:
{
gpio_mode(P1_4,GPO_PP);
break;
}
case PWMA_CH3N_P15:
{
gpio_mode(P1_5,GPO_PP);
break;
}
case PWMA_CH3P_P24:
{
gpio_mode(P2_4,GPO_PP);
break;
}
case PWMA_CH3N_P25:
{
gpio_mode(P2_5,GPO_PP);
break;
}
case PWMA_CH3P_P64:
{
gpio_mode(P6_4,GPO_PP);
break;
}
case PWMA_CH3N_P65:
{
gpio_mode(P6_5,GPO_PP);
break;
}
case PWMA_CH4P_P16:
{
gpio_mode(P1_6,GPO_PP);
break;
}
case PWMA_CH4N_P17:
{
gpio_mode(P1_7,GPO_PP);
break;
}
case PWMA_CH4P_P26:
{
gpio_mode(P2_6,GPO_PP);
break;
}
case PWMA_CH4N_P27:
{
gpio_mode(P2_7,GPO_PP);
break;
}
case PWMA_CH4P_P66:
{
gpio_mode(P6_6,GPO_PP);
break;
}
case PWMA_CH4N_P67:
{
gpio_mode(P6_7,GPO_PP);
break;
}
case PWMA_CH4P_P34:
{
gpio_mode(P3_4,GPO_PP);
break;
}
case PWMA_CH4N_P33:
{
gpio_mode(P3_3,GPO_PP);
break;
}
case PWMB_CH1_P20:
{
gpio_mode(P2_0,GPO_PP);
break;
}
case PWMB_CH1_P17:
{
gpio_mode(P1_7,GPO_PP);
break;
}
case PWMB_CH1_P00:
{
gpio_mode(P0_0,GPO_PP);
break;
}
case PWMB_CH1_P74:
{
gpio_mode(P7_4,GPO_PP);
break;
}
case PWMB_CH2_P21:
{
gpio_mode(P2_1,GPO_PP);
break;
}
case PWMB_CH2_P54:
{
gpio_mode(P5_4,GPO_PP);
break;
}
case PWMB_CH2_P01:
{
gpio_mode(P0_1,GPO_PP);
break;
}
case PWMB_CH2_P75:
{
gpio_mode(P7_5,GPO_PP);
break;
}
case PWMB_CH3_P22:
{
gpio_mode(P2_2,GPO_PP);
break;
}
case PWMB_CH3_P33:
{
gpio_mode(P3_3,GPO_PP);
break;
}
case PWMB_CH3_P02:
{
gpio_mode(P0_2,GPO_PP);
break;
}
case PWMB_CH3_P76:
{
gpio_mode(P7_6,GPO_PP);
break;
}
case PWMB_CH4_P23:
{
gpio_mode(P2_3,GPO_PP);
break;
}
case PWMB_CH4_P34:
{
gpio_mode(P3_4,GPO_PP);
break;
}
case PWMB_CH4_P03:
{
gpio_mode(P0_3,GPO_PP);
break;
}
case PWMB_CH4_P77:
{
gpio_mode(P7_7,GPO_PP);
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief PWM初始化
// @param pwmch PWM通道号及引脚
// @param freq PWM频率(10Hz-3MHz)
// @param duty PWM占空比
// @return void
// Sample usage:
// pwm_init(PWM0_P00, 100, 5000); //初始化PWM0 使用引脚P0.0 输出PWM频率100HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
// PWM_DUTY_MAX在zf_pwm.h文件中 默认为10000
//-------------------------------------------------------------------------------------------------------------------
void pwm_init(PWMCH_enum pwmch,uint32 freq, uint32 duty)
{
uint32 match_temp;
uint32 period_temp;
uint16 freq_div = 0;
P_SW2 |= 0x80;
//GPIO需要设置为推挽输出
pwm_set_gpio(pwmch);
//分频计算,周期计算,占空比计算
freq_div = (sys_clk / freq) >> 16; //多少分频
period_temp = sys_clk / freq ;
period_temp = period_temp / (freq_div + 1) - 1; //周期
if(duty != PWM_DUTY_MAX)
{
match_temp = period_temp * ((float)duty / PWM_DUTY_MAX); // 占空比
}
else
{
match_temp = period_temp + 1; // duty为100%
}
if(PWMB_CH1_P20 <= pwmch) //PWM5-8
{
//通道选择,引脚选择
PWMB_ENO |= (1 << ((2 * ((pwmch >> 4) - 4)))); //使能通道
PWMB_PS |= ((pwmch & 0x03) << ((2 * ((pwmch >> 4) - 4)))); //输出脚选择
// 配置通道输出使能和极性
(*(unsigned char volatile far *) (PWM_CCER_ADDR[pwmch>>5])) |= (uint8)(1 << (((pwmch >> 4) & 0x01) * 4));
//设置预分频
PWMB_PSCRH = (uint8)(freq_div>>8);
PWMB_PSCRL = (uint8)freq_div;
PWMB_BKR = 0x80; //主输出使能 相当于总开关
PWMB_CR1 = 0x01; //PWM开始计数
}
else
{
PWMA_ENO |= (1 << (pwmch & 0x01)) << ((pwmch >> 4) * 2); //使能通道
PWMA_PS |= ((pwmch & 0x07) >> 1) << ((pwmch >> 4) * 2); //输出脚选择
// 配置通道输出使能和极性
(*(unsigned char volatile far *) (PWM_CCER_ADDR[pwmch>>5])) |= (1 << ((pwmch & 0x01) * 2 + ((pwmch >> 4) & 0x01) * 0x04));
//设置预分频
PWMA_PSCRH = (uint8)(freq_div>>8);
PWMA_PSCRL = (uint8)freq_div;
PWMA_BKR = 0x80; // 主输出使能 相当于总开关
PWMA_CR1 = 0x01; //PWM开始计数
}
//周期
(*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6])) = (uint8)(period_temp>>8); //高8位
(*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6] + 1)) = (uint8)period_temp; //低8位
//设置捕获值|比较值
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4])) = match_temp>>8; //高8位
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4] + 1)) = (uint8)match_temp; //低8位
//功能设置
(*(unsigned char volatile far *) (PWM_CCMR_ADDR[pwmch>>4])) |= 0x06<<4; //设置为PWM模式1
(*(unsigned char volatile far *) (PWM_CCMR_ADDR[pwmch>>4])) |= 1<<3; //开启PWM寄存器的预装载功
// P_SW2 &= 0x7F;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief PWM占空比设置
// @param pwmch PWM通道号及引脚
// @param duty PWM占空比
// @return void
// Sample usage: pwm_duty(PWM0_P00, 5000); //初始化PWM0 使用引脚P0.0 输出PWM频率50HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
// PWM_DUTY_MAX在fsl_pwm.h文件中 默认为10000
//-------------------------------------------------------------------------------------------------------------------
void pwm_duty(PWMCH_enum pwmch, uint32 duty)
{
uint32 match_temp;
uint32 arr = ((*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6]))<<8) | (*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6] + 1 ));
// P_SW2 |= 0x80;
if(duty != PWM_DUTY_MAX)
{
match_temp = arr * ((float)duty/PWM_DUTY_MAX); //占空比
}
else
{
match_temp = arr + 1;
}
//设置捕获值|比较值
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4])) = match_temp>>8; //高8位
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4] + 1)) = (uint8)match_temp; //低8位
// P_SW2 &= ~0x80;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief PWM频率设置
// @param pwmch PWM通道号及引脚
// @param freq PWM频率(10Hz-3MHz)
// @param duty PWM占空比
// @return void
// Sample usage: pwm_freq(PWM0_P00, 50, 5000); //修改化PWM0 使用引脚P0.0 输出PWM频率50HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
//-------------------------------------------------------------------------------------------------------------------
void pwm_freq(PWMCH_enum pwmch, uint32 freq, uint32 duty)
{
uint32 match_temp;
uint32 period_temp;
uint16 freq_div = 0;
//分频计算,周期计算,占空比计算
freq_div = (sys_clk / freq) >> 16; // 多少分频
period_temp = sys_clk / freq;
period_temp = period_temp / (freq_div + 1) - 1; // 周期
if(duty != PWM_DUTY_MAX)
{
match_temp = period_temp * ((float)duty / PWM_DUTY_MAX); // 占空比
}
else
{
match_temp = period_temp + 1; // duty为100%
}
// P_SW2 |= 0x80;
if(PWMB_CH1_P20 <= pwmch) //PWM5-8
{
//设置预分频
PWMB_PSCRH = (uint8)(freq_div>>8);
PWMB_PSCRL = (uint8)freq_div;
}
else
{
//设置预分频
PWMA_PSCRH = (uint8)(freq_div>>8);
PWMA_PSCRL = (uint8)freq_div;
}
//周期
(*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6])) = (uint8)(period_temp>>8); //高8位
(*(unsigned char volatile far *) (PWM_ARR_ADDR[pwmch>>6] + 1)) = (uint8)period_temp; //低8位
//设置捕获值|比较值
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4])) = match_temp>>8; //高8位
(*(unsigned char volatile far *) (PWM_CCR_ADDR[pwmch>>4] + 1)) = (uint8)match_temp; //低8位
// P_SW2 &= ~0x80;
}

24
Source/stc32_stc8_usb.c Normal file
View File

@@ -0,0 +1,24 @@
#include "stc32_stc8_usb.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
/************************************************
函数功能USB-CDC串口接收数据的回调函数
函数描述回调函数由USB中断在接收到串口数据时自动调用
回调函数处理完成串口数据后需要返回1
函数返回返回1USB中断服务程序自动完成后续的收尾工作
返回0USB会暂停接收串口数据直到用户自行调用
usb_OUT_done()函数后USB才会重新恢复接收数据
注意事项当函数返回1时用户无需调用usb_OUT_done()
只有返回0时才需要调用usb_OUT_done()进行手动收尾
强烈建议usb_OUT_callback返回1
************************************************/
BOOL usb_OUT_callback()
{
USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
return 1;
}

218
Source/tim.c Normal file
View File

@@ -0,0 +1,218 @@
#include "tim.h"
//-------------------------------------------------------------------------------------------------------------------
// @brief 定时器初始化作为外部计数
// @param tim_n 选择模块
// @return void
// @since v1.0
// Sample usage: ctimer_count_init(CTIM0_P34); //初始化定时器0外部输入为P3.4引脚
// @note 串口1使用定时器1作为波特率发生器
// 串口2使用定时器2作为波特率发生器
// 串口3使用定时器3作为波特率发生器
// 串口4使用定时器4作为波特率发生器
// STC16F仅有定时器0-定时器4这5个定时器。
// 编码器采集数据也需要定时器作为外部计数。
//-------------------------------------------------------------------------------------------------------------------
void ctimer_count_init(CTIMN_enum tim_n)
{
switch(tim_n)
{
case CTIM0_P34:
{
TL0 = 0;
TH0 = 0;
TMOD |= 0x04; //外部计数模式
TR0 = 1; //启动定时器
break;
}
case CTIM1_P35:
{
TL1 = 0x00;
TH1 = 0x00;
TMOD |= 0x40; // 外部计数模式
TR1 = 1; // 启动定时器
break;
}
case CTIM2_P12:
{
T2L = 0x00;
T2H = 0x00;
AUXR |= 0x18; // 设置外部计数模式并启动定时器
break;
}
case CTIM3_P04:
{
T3L = 0;
T3H = 0;
T4T3M |= 0x0c; // 设置外部计数模式并启动定时器
break;
}
case CTIM4_P06:
{
T4L = 0;
T4H = 0;
T4T3M |= 0xc0; // 设置外部计数模式并启动定时器
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 获取计数数值
// @param countch 计数通道号及引脚
// @return uint32 返回计数值
// Sample usage: num = ctimer_count_read(CTIM0_P34);
//-------------------------------------------------------------------------------------------------------------------
uint16 ctimer_count_read(CTIMN_enum tim_n)
{
uint16 dat = 0;
switch(tim_n)
{
case CTIM0_P34:
{
dat = (uint16)TH0 << 8;
dat = ((uint8)TL0) | dat;
break;
}
case CTIM1_P35:
{
dat = (uint16)TH1 << 8;
dat = ((uint8)TL1) | dat;
break;
}
case CTIM2_P12:
{
dat = (uint16)T2H << 8;
dat = ((uint8)T2L) | dat;
break;
}
case CTIM3_P04:
{
dat = (uint16)T3H << 8;
dat = ((uint8)T3L) | dat;
break;
}
case CTIM4_P06:
{
dat = (uint16)T4H << 8;
dat = ((uint8)T4L) | dat;
break;
}
}
return dat;
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 清除计数数值
// @param countch 计数通道号及引脚
// @return void
// Sample usage: ctimer_count_clean(CTIM0_P34);
//-------------------------------------------------------------------------------------------------------------------
void ctimer_count_clean(CTIMN_enum tim_n)
{
switch(tim_n)
{
case CTIM0_P34:
{
TR0 = 0;
TH0 = 0;
TL0 = 0;
TR0 = 1;
break;
}
case CTIM1_P35:
{
TR1 = 0;
TH1 = 0;
TL1 = 0;
TR1 = 1;
break;
}
case CTIM2_P12:
{
AUXR &= ~(1<<4);
T2H = 0;
T2L = 0;
AUXR |= 1<<4;
break;
}
case CTIM3_P04:
{
T4T3M &= ~(1<<3);
T3H = 0;
T3L = 0;
T4T3M |= (1<<3);
break;
}
case CTIM4_P06:
{
T4T3M &= ~(1<<7);
T4H = 0;
T4L = 0;
T4T3M |= (1<<7);
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 定时器周期中断
// @param tim_n 定时器通道号
// @param time_ms 时间(ms)
// @return void
// Sample usage: pit_timer_ms(TIM_0, 10)
// 使用定时器0做周期中断时间10ms一次。
//-------------------------------------------------------------------------------------------------------------------
void pit_timer_ms(TIMN_enum tim_n,uint16 time_ms)
{
uint16 temp;
temp = (uint16)65536 - (uint16)(sys_clk / (12 * (1000 / time_ms)));
if(TIM_0 == tim_n)
{
TMOD |= 0x00; // 模式 0
TL0 = temp;
TH0 = temp >> 8;
TR0 = 1; // 启动定时器
ET0 = 1; // 使能定时器中断
}
else if(TIM_1 == tim_n)
{
TMOD |= 0x00; // 模式 0
TL1 = temp;
TH1 = temp >> 8;
TR1 = 1; // 启动定时器
ET1 = 1; // 使能定时器中断
}
else if(TIM_2 == tim_n)
{
T2L = temp;
T2H = temp >> 8;
AUXR |= 0x10; // 启动定时器
IE2 |= 0x04; // 使能定时器中断
}
else if(TIM_3 == tim_n)
{
T3L = temp;
T3H = temp >> 8;
T4T3M |= 0x08; // 启动定时器
IE2 |= 0x20; // 使能定时器中断
}
else if(TIM_4 == tim_n)
{
T4L = temp;
T4H = temp >> 8;
T4T3M |= 0x80; // 启动定时器
IE2 |= 0x40; // 使能定时器中断
}
}

229
Source/uart.c Normal file
View File

@@ -0,0 +1,229 @@
#include "uart.h"
uint8 busy[5]; //接收忙标志位
//-------------------------------------------------------------------------------------------------------------------
// @brief 串口初始化
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param uart_rx_pin 串口接收引脚
// @param uart_tx_pin 串口发送引脚
// @param baud 串口波特率
// @param tim_n 使用tim_n作为串口波特率发生器(TIM1-TIM4)
// @return NULL
// Sample usage: uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 115200, TIM_2); //初始化串口1 波特率115200 发送引脚使用P31 接收引脚使用P30 ,使用定时器2作为波特率发生器
// @note 串口1使用 定时器1或者定时器2 作为波特率发生器。
// 串口2使用 定时器2 作为波特率发生器。
// 串口3使用 定时器3或者定时器2 作为波特率发生器。
// 串口4使用 定时器4或者定时器2 作为波特率发生器。
// STC32G仅有 定时器0-定时器4这5个定时器。
// 编码器采集数据也需要定时器作为外部计数。
// 如果不同的串口,使用同一个定时器,串口的波特率以最后一个初始化为准
//-------------------------------------------------------------------------------------------------------------------
void uart_init(UARTN_enum uart_n, UARTPIN_enum uart_rx_pin, UARTPIN_enum uart_tx_pin, uint32 baud, TIMN_enum tim_n)
{
uint16 brt;
brt = (uint16)(65536 - (sys_clk/baud/4));
switch(uart_n)
{
case UART_1:
{
if(TIM_1 == tim_n)
{
SCON |= 0x50;
TMOD |= 0x00;
TL1 = brt;
TH1 = brt >> 8;
AUXR |= 0x40;
TR1 = 1;
busy[1] = 0;
}
else if(TIM_2 == tim_n)
{
SCON |= 0x50;
T2L = brt;
T2H = brt >> 8;
AUXR |= 0x15;
}
P_SW1 &= ~(0x03<<6);
if((UART1_RX_P30 == uart_rx_pin) && (UART1_TX_P31 == uart_tx_pin))
{
P_SW1 |= 0x00;
}
else if((UART1_RX_P36 == uart_rx_pin) && (UART1_TX_P37 == uart_tx_pin))
{
P_SW1 |= 0x40;
}
else if((UART1_RX_P16 == uart_rx_pin) && (UART1_TX_P17 == uart_tx_pin))
{
P_SW1 |= 0x80;
}
else if((UART1_RX_P43 == uart_rx_pin) && (UART1_TX_P44 == uart_tx_pin))
{
P_SW1 |= 0xc0;
}
busy[1] = 0;
ES = 1;
break;
}
case UART_2:
{
if(TIM_2 == tim_n)
{
S2CON |= 0x50;
T2L = brt;
T2H = brt >> 8;
AUXR |= 0x14;
}
P_SW2 &= ~(0x01<<0);
if((UART2_RX_P10 == uart_rx_pin) && (UART2_TX_P11 == uart_tx_pin))
{
P_SW2 |= 0x00;
}
else if((UART2_RX_P46 == uart_rx_pin) && (UART2_TX_P47 == uart_tx_pin))
{
P_SW2 |= 0x01;
}
IE2 |= 0x01 << 0; //允许串行口2中断
busy[2] = 0;
break;
}
case UART_3:
{
if(TIM_2 == tim_n)
{
S3CON |= 0x10;
T2L = brt;
T2H = brt >> 8;
AUXR |= 0x14;
}
else if(TIM_3 == tim_n)
{
S3CON |= 0x50;
T3L = brt;
T3H = brt >> 8;
T4T3M |= 0x0a;
}
P_SW2 &= ~(0x01<<1);
if((UART3_RX_P00 == uart_rx_pin) && (UART3_TX_P01 == uart_tx_pin))
{
P_SW2 |= 0x00;
}
else if((UART3_RX_P50 == uart_rx_pin) && (UART3_TX_P51 == uart_tx_pin))
{
P_SW2 |= 0x02;
}
IE2 |= 0x01<<3; //允许串行口3中断
busy[3] = 0;
break;
}
case UART_4:
{
if(TIM_2 == tim_n)
{
S4CON |= 0x10;
T2L = brt;
T2H = brt >> 8;
AUXR |= 0x14;
}
else if(TIM_4 == tim_n)
{
S4CON |= 0x50;
T4L = brt;
T4H = brt >> 8;
T4T3M |= 0xa0;
}
P_SW2 &= ~(0x01<<2);
if((UART4_RX_P02 == uart_rx_pin) && (UART4_TX_P03 == uart_tx_pin))
{
P_SW2 |= 0x00;
}
else if((UART4_RX_P52 == uart_rx_pin) && (UART4_TX_P53 == uart_tx_pin))
{
P5M0 = 0x00;
P5M1 = 0x01<<2;//P5.2 需要设置为高阻
P_SW2 |= 0x04;
}
IE2 |= 0x01<<4; //允许串行口4中断
busy[4] = 0;
break;
}
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 串口字节输出
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param dat 需要发送的字节
// @return void
// Sample usage: uart_putchar(UART_1,0xA5); // 串口1发送0xA5
//-------------------------------------------------------------------------------------------------------------------
void uart_putchar(UARTN_enum uart_n,uint8 dat)
{
switch(uart_n)
{
case UART_1:
while (busy[1]);
busy[1] = 1;
SBUF = dat;
break;
case UART_2:
while (busy[2]);
busy[2] = 1;
S2BUF = dat;
break;
case UART_3:
while (busy[3]);
busy[3] = 1;
S3BUF = dat;
break;
case UART_4:
while (busy[4]);
busy[4] = 1;
S4BUF = dat;
break;
}
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 串口发送数组
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param *buff 要发送的数组地址
// @param len 发送长度
// @return void
// Sample usage: uart_putbuff(UART_1,&a[0],5);
//-------------------------------------------------------------------------------------------------------------------
void uart_putbuff(UARTN_enum uart_n,uint8 *p,uint32 len)
{
while(len--)
uart_putchar(uart_n,*p++);
}
//-------------------------------------------------------------------------------------------------------------------
// @brief 串口发送字符串
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param *str 要发送的字符串地址
// @return void
// Sample usage: uart_putstr(UART_1,"i lvoe you");
//-------------------------------------------------------------------------------------------------------------------
void uart_putstr(UARTN_enum uart_n,uint8 *str)
{
while(*str)
{
uart_putchar(uart_n, *str++);
}
}