// Electric vehicle double closed loop program, using double closed loop mode to control the motor for optimal speed performance and limit the maximum current of the motor. This application uses two CCP components: CCP1 is used for PWM output to control the motor voltage, while CCP2 triggers AD, timer TMR2, TMR1, INT interrupt, RB port level change interrupt, watchdog, and 6 general-purpose I/O ports.
#define AND 0xe0 // Status acquisition bits 5,6,7
#define CURA 0x0a // Sum of current loop ratio and integral coefficient
#define CURB 0x09 // Current loop proportional coefficient
#define THL 0x6400 // Current loop maximum output
#define FULLDUTY 0x0FF // High time when duty ratio is 1
#define SPEA 0x1d // Sum of speed loop ratio and integral coefficient
#define SPEB 0x1c // Speed loop proportional coefficient
#define GCURHILO 0x0330 // Maximum output of the speed loop
#define GCURH 0x33 // Maximum given current
#define GSPEH 0x67 // Maximum speed reference
#define TSON 0x38 // Handle opening voltage is 1.1V, TSON*2 is the handle opening voltage after braking (2.2V)
#define VOLON 0x4c // Low voltage protection re-start voltage (3.0V or 33V)
#define VOLOFF 0x49 // Low voltage protection shutdown voltage (2.86V or 31.5V)
volatile unsigned char DELAYH, DELAYL, oldstate, speed,
speedcount, tsh, count_ts, count_vol, gcur, currenth,
voltage; // Register definition
static bit sp1, spe, ts, volflag, spep, lowpower,
off, shutdown, curpid; // Flag definition
static volatile unsigned char new[10] = {0xaf, 0xbe, 0xff, 0x7e, 0xcf,
0xff, 0xd7, 0x77, 0xff, 0xff}; // Status register table
//------------ PIC16F877 initialization subroutine ------------
void INIT877()
{
PORTC = 0X0FF; // Turn off all MOSFETs
TRISC = 0X02; // Set C port as output
PIE1 = 0X00; // Interrupt register initialization, disable all interrupts
TRISA = 0XCF; // Set RA4, RA5 as output
TRISB = 0XEF; // RB port high three bits as input, collect motor three-phase Hall signal
PORTC = new[(PORTB & AND) >> 5]; // Collect first Hall signal, output corresponding signal, turn on two MOSFETs
T2CON = 0X01; // TMR2 prescaler set to 4
CCPR1L = 0X0FF; // Initial PWM output full duty
CCP1CON = 0X0FF; // CCP1 set to PWM mode
CCP2CON = 0X0B; // CCP2 set to special mode to trigger AD
ADCON0 = 0X81; // AD clock divided by 32, enable AD, select AN0 channel for handle voltage
TMR2 = 0X00; // TMR2 register initialization
TMR1H = 0X00; // TMR1 register initialization
TMR1L = 0X00;
T1CON = 0X00; // TMR1 prescaler set to 1
CCPR2H = 0X08;
CCPR2L = 0X00; // Current sampling period set to TAD = 512μs
PR2 = 0XC7; // PWM frequency set to 5kHz
ADCON1 = 0X02; // AD results left-aligned
OPTION = 0XFB; // INT rising edge trigger
TMR2ON = 1; // Start PWM
INTCON = 0XD8; // Enable global and peripheral interrupts, enable RB port interrupt
ADIE = 1; // Enable AD interrupt
speedcount = 0x00; // Speed count register
speed = 0x7f; // Speed holding register
spe = 1; // Low speed flag
sp1 = 1; // Low speed flag
oldstate = 0x0ff; // Initial state setting, different from other states
count_ts = 0x08; // Current sampling 8 times, collect 1 handle
count_vol = 0x00; // Sample 256 handles, collect 1 battery voltage
ts = 1; // Flag to collect handle value
ADGO = 1; // AD sampling enabled
TMR1ON = 1; // Start CCP2 parts
}
//------------ Delay subroutine ---------------
#pragma interrupt_level 1
void DELAY1(char x)
{
DELAYH = x; // Delay parameter setting
#asm
DELAY2 MOVLW 0X06
MOVWF DELAYL
DELAY1 DECFSZ DELAYL
GOTO DELAY1
DECFSZ DELAYH
GOTO DELAY2
#endasm
}
//----------- Status collection subroutine ----------------------
void sample()
{
char state1, state2, state3, x;
do {
x = 1;
state1 = (PORTB & AND); // Hall signal acquisition
DELAY1(x);
state2 = (PORTB & AND);
} while (state1 - state2); // Continue collecting if three samples differ
if (state1 != oldstate) // If sampling result is different from last time
{
oldstate = state1; // Update old state
state1 = (oldstate >> 5);
PORTC = new[state1]; // Output corresponding signal, trigger two MOSFETs
if (sp1 == 1) {
spe = 1;
sp1 = 0;
}
else {
spe = 0;
sp1 = 0;
speedcount <<= 1;
state3 = (TMR1H >> 2); // Count speed
speed = speedcount + state3; // Add 1 every 256μs
}
speedcount = 0;
}
}
//-----------------AD sampling subroutine --------------------
void AD()
{
char x;
ADIF = 0; // Clear AD interrupt flag
if (ts == 1) { // If handle is sampled, sample handle value
CHS0 = 1; // Select current sampling channel
count_vol = count_vol + 1; // Battery sample count register
spep = 1; // Set speed closed loop operation flag
ts = 0;
tsh = ADRESH; // Save handle value
if (count_vol == 0) { // If battery sampling time is up, select AN2 channel and collect battery voltage
CHS0 = 0;
CHS1 = 1;
volflag = 1;
x = 1;
DELAY1(x);
ADGO = 1;
}
}
else if (volflag == 1) { // Battery sampled and processed accordingly
CHS1 = 0;
CHS0 = 1;
volflag = 0;
voltage = ADRESH;
lowpower = 1;
}
else { // Other, this is current sampling interrupt
speedcount = speedcount + 1; // Increment speedcount for speed measurement
if (speedcount > 0x3d) sp1 = 1; // If speed is lower than 1000000μs/(512μs*3eh*3), consider it as low speed
currenth = ADRESH;
curpid = 1;
count_ts = count_ts - 1;
if (count_ts == 0) { // If handle time is up, switch to handle sampling channel
CHS0 = 0;
count_ts = 0x08;
ts = 1;
x = 1;
DELAY1(x);
ADGO = 1;
}
}
}
//-------------Brake processing subroutine ------------------
void BREAKON()
{
char x;
off = 0; // Clear off flag, not reset if interference
shutdown = 0;
if (RB0 == 1) { // If brake signal is true, stop output voltage
ADIE = 0; // Disable AD interrupt
INTE = 0; // Disable brake interrupt
CCPR1L = FULLDUTY; // Output voltage 0
TMR1ON = 0; // Disable CCP2, no longer trigger AD
for (; ADGO == 1;) continue; // Wait for sampling to end
ADIF = 0; // Clear ADIF bit
CHS0 = 0; // Select channel 0 for handle sampling
CHS1 = 0;
x = 1;
DELAY1(x);
do {
ADGO = 1;
for (; ADIF == 0;) continue;
ADIF = 0;
CCPR1L = FULLDUTY;
asm("CLRWDT");
tsh = (ADRESH >> 1);
} while (tsh > TSON || RB0 == 1); // Execute while handle value > 2.2V or brake continues
off = 1; // Reset flag
}
}
//---------Underprotected subroutine -------------------
void POWER()
{
char x;
lowpower = 0;
voltage >>= 1; // Convert voltage to 7 bits for single-byte operation
if (voltage < voloff) {
ADIE = 0;
INTE = 0;
TMR1ON = 0;
CCPR1L = FULLDUTY;
for (; ADGO == 1;) continue;
ADIF = 0;
CHS0 = 0;
CHS1 = 1;
x = 1;
DELAY1(x);
do {
ADGO = 1;
for (; ADIF == 0;) continue;
ADIF = 0;
voltage = (ADRESH >> 1);
CCPR1L = FULLDUTY;
asm("CLRWDT");
} while (voltage < volon);
off = 1; // Reset flag
}
}
//------------ Current loop operation subroutine -----------------
void CURPI()
{
static int curep = 0x00, curek = 0x00, curuk = 0x00;
union data {
int pwm;
char a[2];
} b; // Define current loop arithmetic register
curpid = 0; // Clear current operation flag
curep = curek * CURB; // Calculate product of last deviation and scale factor
if (currenth < 2) currenth = 2; // If current is zero, consider small current to help speed drop
currenth >>= 1;
curek = gcur - currenth; // Calculate this deviation
curuk = curuk + curek * CURA - curep; // PI operation result
if (curuk < 0x00) { // If output is less than zero, treat as zero
curuk = 0;
CCPR1L = FULLDUTY;
CCP1X = 0;
CCP1Y = 0;
}
else if (curuk - THL >= 0) { // If output exceeds limit, output max voltage
curuk = THL;
CCPR1L = 0;
CCP1X = 0;
CCP1Y = 0;
}
else { // Otherwise, output corresponding high time proportionally
b.pwm = THL - curuk;
b.pwm <<= 1;
CCPR1L = b.a[1]; // High nibble of PWM register
if (b.pwm & 0x80) CCP1X = 1;
else CCP1X = 0;
if (b.pwm & 0x40) CCP1Y = 1;
else CCP1Y = 0;
}
}
//---------------Speed loop operation subroutine -----------------------
void SPEPI()
{
static int speep = 0x00, speek = 0x00, speuk = 0x00;
int tsh1, speed1; // Speed register definition
spep = 0; // Clear speed calculation flag
if (spe == 1) speed1 = 0x00; // If speed is too low, consider it as zero
else speed1 = 0x7f - speed; // Otherwise calculate actual speed
if (speed1 < 0) speed1 = 0;
speep = speek * SPEB;
tsh1 = tsh - 0x38; // Get handle value for calculation
speek = tsh1 - speed1;
if (tsh1 < 0) {
speuk = 0;
gcur = 0;
}
else {
if (tsh1 >= GSPEH) // Limit maximum speed
tsh1 = GSPEH;
speuk = speuk + speek * SPEA - speep; // Calculate speed loop output
if (speuk <= 0X00) {
speuk = 0x00;
gcur = 0x00;
}
else if (speuk > GCURHILO) { // Limit speed loop output (approx. 12A)
speuk = GCURHILO;
gcur = GCURH;
}
else {
gcur = (speuk >> 4) & 0x0ff;
}
}
}
//----------- main program -------------------------
void main()
{
for (;;)
{
INIT877(); // After MCU reset, initialize first
off = 0; // Clear reset flag
for (; off == 0;) { // If reset flag is zero, execute the following program, otherwise reset
if (curpid == 1) CURPI(); // Current PI operation
else if (spep == 1) SPEPI(); // Speed PI operation
else if (lowpower == 1) POWER();
else if (shutdown == 1) BREAKON();
asm("CLRWDT");
}
}
}
//---------Interrupt service subroutine ---------------------
#pragma interrupt_level 1
void interrupt INTS(void)
{
if (RBIF == 1) {
RBIF = 0;
sample();
}
else if (ADIF == 1) AD();
else if (INTF == 1) {
shutdown = 1;
INTF = 0;
}
}Lamp Pole
Yixing Futao Metal Structural Unit Co. Ltd. is com manded of Jiangsu Futao Group.
It is located in the beach of scenic and rich Taihu Yixing with good transport service.
The company is well equipped with advanced manufacturing facilities.
We own a large-sized numerical control hydraulic pressure folding machine with once folding length 16,000mm and the thickness 2-25mm.
We also equipped with a series of numerical control conveyor systems of flattening, cutting, folding and auto-welding, we could manufacture all kinds of steel poles and steel towers.
Our main products: high & medium mast lighting, road lighting, power poles, sight lamps, courtyard lamps, lawn lamps, traffic signal poles, monitor poles, microwave communication poles, etc. Our manufacturing process has been ISO9001 certified and we were honored with the title of the AAA grade certificate of goodwill"
Presently 95% of our products are far exported to Europe, America, Middle East, and Southeast Asia, and have enjoyed great reputation from our customers,
So we know the demand of different countries and different customers.
We are greatly honored to invite you to visit our factory and cheerfully look forward to cooperating with you.


Lighting Pole,Steel Lamp Pole,Street Light Poles,Garden Lamp Post
JIANGSU XINJINLEI STEEL INDUSTRY CO.,LTD , https://www.chinasteelpole.com